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
42,942 changes: 17,329 additions & 25,613 deletions package-lock.json

Large diffs are not rendered by default.

19 changes: 16 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,34 @@
"@testing-library/jest-dom": "^5.11.10",
"@testing-library/react": "^11.2.6",
"@testing-library/user-event": "^12.8.3",
"axios": "^1.4.0",
"bootstrap": "^5.3.0",
"eslint-config-wesbos": "^3.2.3",
"lodash": "^4.17.21",
"normalizr": "^3.6.2",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-scripts": "4.0.3",
"react-hook-form": "^6.15.4",
"react-redux": "^8.0.7",
"react-router": "^6.12.0",
"react-router-dom": "^6.12.0",
"react-scripts": "^5.0.1",
"react-sparklines": "^1.7.0",
"redux": "^4.2.1",
"redux-promise": "^0.6.0",
"web-vitals": "^1.1.1"
},
"scripts": {
"start": "react-scripts start",
"start": "react-scripts --openssl-legacy-provider start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
"react-app/jest",
"wesbos"
]
},
"browserslist": {
Expand Down
24 changes: 0 additions & 24 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -1,25 +1 @@
import logo from './logo.svg';
import './App.css';

function App() {
return (
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
);
}

export default App;
16 changes: 16 additions & 0 deletions src/actions/actions-index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import axios from 'axios';

export const GET_CITY = 'GET_CITY';

const apiKey = '536b99823dd5364f3a29be3867644595';
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

apiKey should not be hard coded like this - better to use a .env file


export function getCityWeather(value) {
const data = axios.get(
`https:/api.openweathermap.org/data/2.5/forecast?q=${value}&appid=${apiKey}&units=imperial`
);

return {
type: GET_CITY,
payload: data,
};
}
112 changes: 112 additions & 0 deletions src/components/city-search.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/* eslint-disable no-param-reassign */
import '../index.css';

import { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import _ from 'lodash';
import {
Sparklines,
SparklinesLine,
SparklinesReferenceLine,
} from 'react-sparklines';
import { getCityWeather } from '../actions/actions-index';

const SearchCity = () => {
const [city, setCity] = useState('');
const weather = useSelector((state) => state);

const dispatch = useDispatch();

const handleFormSubmit = () => {
dispatch(getCityWeather(city));
setCity('');
};

function renderWeather() {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Stay consistent with your functions (expressions vs declarations)

function renderTemp(temp) {
temp = temp.map((item) => item.main.temp);
return (
<div>
<Sparklines data={temp}>
<SparklinesLine color="orange" />
<SparklinesReferenceLine type="mean" />
</Sparklines>
<div>{Math.floor(temp[0])} F</div>
</div>
);
}

function renderPressure(pressure) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

would be cleaner to move the render functionality to its own component

console.log(pressure);
pressure = pressure.map((item) => item.main.pressure);
return (
<div>
<Sparklines data={pressure}>
<SparklinesLine color="green" />
<SparklinesReferenceLine type="mean" />
</Sparklines>
<div className="col-md-4">{pressure[0]} hPa</div>
</div>
);
}

function renderHumidity(humidity) {
humidity = humidity.map((item) => item.main.humidity);
return (
<div>
<Sparklines data={humidity}>
<SparklinesLine color="">{humidity}</SparklinesLine>
<SparklinesReferenceLine type="mean" />
</Sparklines>
<div>{humidity[0]} %</div>
</div>
);
}
if (!_.isEmpty(weather)) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

nice use of lodash

return weather.map((data) => (
<tr key={data.city.id}>
<td>{data.city.name}</td>
<td>{renderTemp(data.list)}</td>
<td>{renderPressure(data.list)}</td>
<td>{renderHumidity(data.list)}</td>
</tr>
));
}
}

return (
<div className="form-group">
<form>
<div className="input-group mb-3">
<input
type="text"
className="form-control"
placeholder="Get the Weather for a City"
onChange={(e) => setCity(e.target.value)}
value={city}
/>
<button
className="btn btn-outline btn-primary"
type="button"
onClick={handleFormSubmit}
>
Submit
</button>
</div>
</form>
<table className="table">
<thead>
<tr>
<th>City</th>
<th>Temperature (F)</th>
<th>Pressure (hPa)</th>
<th>Humidity (%)</th>
</tr>
</thead>
<tbody>{renderWeather()}</tbody>
</table>
</div>
);
};

export default SearchCity;
14 changes: 14 additions & 0 deletions src/components/header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import '../index.css';

const header = (props) => (
<div className="custom">
<div className="jumbotron text-center">
<div className="container">
<h1 className="jumbotron-heading">Search the weather for a city</h1>
</div>
</div>
<div className="container">{props.children}</div>
</div>
);

export default header;
4 changes: 4 additions & 0 deletions src/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,7 @@ code {
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
monospace;
}

.custom {
margin-top: 30px
}
27 changes: 17 additions & 10 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import 'bootstrap/dist/css/bootstrap.css';

import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware } from 'redux';
import { Provider } from 'react-redux';

import promise from 'redux-promise';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

import Header from './components/header';
import CitySearch from './components/city-search';
import cityReducer from './reducers/reducer-cities';

const store = applyMiddleware(promise)(createStore);

ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
<Provider store={store(cityReducer)}>
<Header>
<CitySearch />
</Header>
</Provider>,
document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
15 changes: 15 additions & 0 deletions src/reducers/reducer-cities.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { GET_CITY } from '../actions/actions-index';

const initialState = [];

// eslint-disable-next-line default-param-last
const cityReducer = (state = initialState, action) => {
switch (action.type) {
case GET_CITY:
return [...state, action.payload.data];
default:
return state;
}
};

export default cityReducer;