Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion .eslintrc.json
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
{
"extends": "next/core-web-vitals"
"extends": "next/core-web-vitals",
"rules": {
"redux/no-deprecated-api": "off"
}

}

36 changes: 36 additions & 0 deletions app/components/SearchInput.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { fetchWeatherData } from '../redux/weatherService';
import React from 'react';
import { useDispatch } from 'react-redux';
import { useState } from 'react';
import weatherConditions from './weatherConditions';


const SearchInput = () => {
const dispatch = useDispatch()
const [city, setCity] = useState('');
const [error, setError] = useState(null);
const handleSearch = () => {
if (!city.trim()) {
setError('Please enter a city name');
return;
}
dispatch(fetchWeatherData(city))
setCity('');
setError(null);
};

return (
<div>
<input
type="text"
value={city}
onChange={(event) => setCity(event.target.value)}
placeholder="Enter a city..."
/>
<button onClick={handleSearch}>Search</button> {}
{error && <div>{error}</div>}
</div>
);
};

export default SearchInput;
22 changes: 22 additions & 0 deletions app/components/WeatherChart.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React from 'react';
import { connect } from 'react-redux';
import { Sparklines, SparklinesLine } from 'react-sparklines';

const WeatherChart = ({ weatherData }) => {
const data = weatherData ? weatherData.map(entry => entry.main.temp) : [];

return (
<div>
<Sparklines data={data}>
<SparklinesLine color="blue" />
</Sparklines>
</div>
);
};


const mapStateToProps = (state) => ({
weatherData: state.weatherData
});

export default connect(mapStateToProps)(WeatherChart);
10 changes: 10 additions & 0 deletions app/components/WeatherSparkline.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Sparklines, SparklinesLine, SparklinesReferenceLine } from "react-sparklines";

const WeatherSparkLine = ({ data, color }) => {
return (<Sparklines data={data}>
<SparklinesLine color={color}/>
<SparklinesReferenceLine type="avg" />
</Sparklines>)
}

export default WeatherSparkLine
49 changes: 49 additions & 0 deletions app/components/weatherConditions.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react'
import { useSelector } from 'react-redux'
import WeatherSparkLine from './WeatherSparkline'

const weatherConditions = (city) => {
const weatherStats = {name:city.city.name, id:city.city.id, temp:[], humidity:[], pressure:[]}

city.list.forEach((dataPoint => {

weatherStats.temp.push(dataPoint.main.temp)
weatherStats.humidity.push(dataPoint.main.humidity)
weatherStats.pressure.push(dataPoint.main.pressure)
}))
return weatherStats

}

export const RenderConditions = () => {
const cities = useSelector((state) => {
state.weather.city
})
return cities.map((city) => {
const weatherData = weatherConditions(city)

return (

<table key={city.city.id} className="row">
<tbody>
<tr className="row">
<td className="city-name col-md-3">{city.city.name}</td>
<td className="col-md-3">
<WeatherSparkLine data={weatherData.temp} color="blue" />
<p>{Math.round(weatherData.temp[0])}°</p>
</td>
<td className="col-md-3">
<WeatherSparkLine data={weatherData.pressure} color="green" />
<p>{weatherData.pressure[0]}</p>
</td>
<td className="col-md-3">
<WeatherSparkLine data={weatherData.humidity} color="orange" />
<p>{weatherData.humidity[0]} %</p>
</td>
</tr>
</tbody>
</table>

)
});
}
19 changes: 11 additions & 8 deletions app/layout.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
import './globals.css'
'use client'
import 'bootstrap/dist/css/bootstrap.min.css';
import { Provider } from 'react-redux'
import { Inter } from 'next/font/google'
import store from './redux/store'

const inter = Inter({ subsets: ['latin'] })

export const metadata = {
title: 'Create Next App',
description: 'Generated by create next app',
}
const inter = Inter({ subsets: ['latin'] })

export default function RootLayout({ children }) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
<Provider store={store}>
<body className={inter.className}>
{children}
</body>
</Provider>
</html>
)
}
}
112 changes: 21 additions & 91 deletions app/page.js
Original file line number Diff line number Diff line change
@@ -1,95 +1,25 @@
import Image from 'next/image'
import styles from './page.module.css'
'use client'
import React from 'react';
import { Provider } from 'react-redux';
import store from './redux/store';
import WeatherChart from './components/WeatherChart';
import SearchInput from './components/SearchInput';

export default function Home() {
return (
<main className={styles.main}>
<div className={styles.description}>
<p>
Get started by editing&nbsp;
<code className={styles.code}>app/page.js</code>
</p>
<div>
<a
href="https://vercel.com?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
target="_blank"
rel="noopener noreferrer"
>
By{' '}
<Image
src="/vercel.svg"
alt="Vercel Logo"
className={styles.vercelLogo}
width={100}
height={24}
priority
/>
</a>
</div>
</div>

<div className={styles.center}>
<Image
className={styles.logo}
src="/next.svg"
alt="Next.js Logo"
width={180}
height={37}
priority
/>
</div>

<div className={styles.grid}>
<a
href="https://nextjs.org/docs?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Docs <span>-&gt;</span>
</h2>
<p>Find in-depth information about Next.js features and API.</p>
</a>

<a
href="https://nextjs.org/learn?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Learn <span>-&gt;</span>
</h2>
<p>Learn about Next.js in an interactive course with&nbsp;quizzes!</p>
</a>
const Page = () => {
return (
<div>
<h1>Weather App</h1>
<SearchInput/>
<WeatherChart />
</div>
);
};

<a
href="https://vercel.com/templates?framework=next.js&utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Templates <span>-&gt;</span>
</h2>
<p>Explore the Next.js 13 playground.</p>
</a>
const PageWithProvider = () => (
<Provider store={store}>
<Page />
</Provider>
);

<a
href="https://vercel.com/new?utm_source=create-next-app&utm_medium=appdir-template&utm_campaign=create-next-app"
className={styles.card}
target="_blank"
rel="noopener noreferrer"
>
<h2>
Deploy <span>-&gt;</span>
</h2>
<p>
Instantly deploy your Next.js site to a shareable URL with Vercel.
</p>
</a>
</div>
</main>
)
}
export default PageWithProvider;
9 changes: 9 additions & 0 deletions app/redux/rootReducer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use client'
import weatherSlice from "./weatherService";
import { combineReducers } from '@reduxjs/toolkit'

const rootReducer = combineReducers({
reducer: weatherSlice
})

export default rootReducer
9 changes: 9 additions & 0 deletions app/redux/store.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
'use client'
import rootReducer from "./rootReducer";
import { configureStore } from '@reduxjs/toolkit'

const store = configureStore({
reducer: rootReducer
})

export default store
39 changes: 39 additions & 0 deletions app/redux/weatherService.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import axios from 'axios'
import {createAsyncThunk, createSlice} from '@reduxjs/toolkit'

export const fetchWeatherData = createAsyncThunk(
'weather/fetchWeatherData', async (city) => {
try {
const response = await axios.get(`https://api.openweathermap.org/data/2.5/forecast?q=${city}&appid=4d2230e28dd5ff342317c6687cd2d078`)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

recommend adding appid as a variable here

console.log(response)
return response.data
} catch (error) {
console.log('ur a bad coder')
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove console logs as they are just used for troubleshooting - and not a bad coder, just need more practice :)

}
}
)

const initialState = {city:[], status:'idle', error:null}

export const weatherSlice = createSlice({
name: 'weather',
initialState,
extraReducers: builder => {
builder.addCase(fetchWeatherData.pending, state => {
state.status = 'Loading'
state.error = null
})
builder.addCase(fetchWeatherData.fulfilled, (state, action) => {
state.status = 'Got Eem',
state.error = null
state.city.push(action.payload)
});
builder.addCase(fetchWeatherData.rejected, state => {
state.status = 'Failed',
state.error = action.error.message
return state;
})
}
})

export default weatherSlice.reducer
10 changes: 10 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,13 @@
const nextConfig = {}

module.exports = nextConfig

const path = require('path');

module.exports = {
// Define custom directory aliases
webpack(config) {
config.resolve.alias['@redux'] = path.join(__dirname, 'app', 'redux');
return config;
},
};
Loading