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
28 changes: 28 additions & 0 deletions assignments/hackyourtemperature/Router/weather.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import express from "express";
import keys from "../source/keys.js";
export const router = express.Router();
import fetch from "node-fetch";

router.get("/", (req, res) => {
res.render("home", {
welcomeMessage: "hello discover weather for any city you want",
});
});
router.post("/", async (req, res) => {
const { cityName } = req.body;
if (!cityName) {
res.status(400).render("home", { errorMessage: "City is required" });
Copy link

Choose a reason for hiding this comment

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

There should be a return statement to prevent further execution.

}
const URL = `https://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${keys.API_KEY}&units=metric`;
try {
const response = await fetch(URL);

const data = await response.json();
res.render("weatherShow", { data });
Copy link

Choose a reason for hiding this comment

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

This is a point of preference and overall API design, but the instructions asked to return temperature info for the selected city. You are returning the entire blob of data, which then needs to be parsed by the requesting client. This can work, but the client needs to be aware of this fact.

} catch (err) {
console.error(
`faild fetch data weather err fetchApi ${response.statusText} ${response.status}`
);
res.status(500).render("home", { errorMessage: "City is not found!" });
}
});
27 changes: 27 additions & 0 deletions assignments/hackyourtemperature/__tests__/app.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import express from "express";
import app from "../app";
import request from "supertest";

describe("Get /weather", () => {
it("should return hello world", async () => {
const response = await request(app).get("/weather");
expect(response.status).toBe(200);
expect(response.text).toContain(
"hello discover weather for any city you want"
);
});
it("should return the city name in respons", async () => {
const response = await request(app)
.post("/weather")
.send({ cityName: "Amsterdam" });

expect(response.status).toBe(200);
expect(response.text).toContain("Amsterdam");
});
it("should return 400 if city is missing", async () => {
const response = await request(app).post("/weather").send({});

expect(response.status).toBe(400);
expect(response.text).toContain("City is required");
});
});
23 changes: 23 additions & 0 deletions assignments/hackyourtemperature/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import express from "express";
import path from "path";
import expressHandlebars from "express-handlebars";
import { fileURLToPath } from "url";
import { router } from "./Router/weather.js";
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const app = express();


// Middleware
app.use(express.json());
app.use(express.static(path.join(__dirname, "public")));
app.use(express.urlencoded({ extended: true }));
app.use("/weather", router);

// Handelbars setup
app.engine("hbs", expressHandlebars.engine({ extname: ".hbs" }));
app.set("view engine", "hbs");
app.set("views", path.join(__dirname, "views"));

export default app;
3 changes: 3 additions & 0 deletions assignments/hackyourtemperature/config-files/babel.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
presets: [["@babel/preset-env", { targets: { node: "current" } }]],
};
6 changes: 6 additions & 0 deletions assignments/hackyourtemperature/config-files/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
transform: {
"^.+\\.js$": "babel-jest",
},
testEnvironment: "node",
};
4 changes: 4 additions & 0 deletions assignments/hackyourtemperature/jest.config.js
Copy link

Choose a reason for hiding this comment

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

To clarify, you should have replaced this and the babe.config.csj files with the examples from the assignment instructions.

Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
export default {
testEnvironment: "node",
transform: {},
};
30 changes: 30 additions & 0 deletions assignments/hackyourtemperature/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "hackyourtemperature",
"version": "1.0.0",
"description": "",
"main": "index.js",
Copy link

Choose a reason for hiding this comment

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

This should point to server.js since that's your main file.

"type": "module",
"scripts": {
"test": "cross-env NODE_OPTIONS=--experimental-vm-modules jest",
"start": "node server.js",
"dev": "nodemon server.js"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"express": "^5.1.0",
"express-handlebars": "^8.0.3",
"node-fetch": "^3.3.2"
},
"devDependencies": {
"@babel/core": "^7.28.0",
"@babel/preset-env": "^7.28.0",
"babel-jest": "^30.0.5",
"cross-env": "^10.0.0",
"jest": "^30.0.5",
"nodemon": "^3.1.10",
"superset": "^2.0.1",
Copy link

Choose a reason for hiding this comment

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

Possibly a typo? I don't see this package used anywhere in the project.

"supertest": "^7.1.4"
}
}
42 changes: 42 additions & 0 deletions assignments/hackyourtemperature/public/css/style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
body{
margin: 0;
padding: 0;
box-sizing: border-box;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color:#333;

min-height: 100vh;
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #74ebd5, #ACB6E5);
}
html{
font-size: 16px;

}
.city-search input{
width:100%;
max-width: 400px;
padding: 10px;
border-radius: 8px;
border: none;
margin: 10px 0;
}
.city-search input:hover{
border:2px solid #74ebd5;
}
.search-btn{
padding: 10px 20px;
border-radius: 8px;
border: none;
background-color: #ACB6E5;
color: white;
}
.search-btn:hover{
background-color: white;
color: #ACB6E5;
cursor: pointer;
}

5 changes: 5 additions & 0 deletions assignments/hackyourtemperature/server.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import app from "./app.js";
const PORT = process.env.PORT || 3000;
Copy link

Choose a reason for hiding this comment

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

Great that you're using an environment variable with a fallback.

app.listen(PORT, () => {
console.log(`server is running on prot ${PORT}`);
});
1 change: 1 addition & 0 deletions assignments/hackyourtemperature/source/keys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default { API_KEY: "21bf76a65461435a76771d5a2caac6c8" };
24 changes: 24 additions & 0 deletions assignments/hackyourtemperature/views/home.hbs
Copy link

Choose a reason for hiding this comment

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

This is an excellent addition that was not required in the instructions 👏

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>My Websit</title>
<link rel="stylesheet" href="css/style.css">
</head>
<body>
<h1>hello from backend to front end</h1>
<p>Welcome to my website!</p>
<form action="/weather" method="post">
<div class="city-search">
<p>{{welcomeMessage}} </p>
<label for="city">Enter City:</label>
<input type="text" id="city" name="cityName" required>
</div>
<button class="search-btn">search</button>

</form>
<h2 id="weather-data">{{errorMessage}}.</h2>

</body>
</html>
12 changes: 12 additions & 0 deletions assignments/hackyourtemperature/views/layouts/main.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>main</title>
</head>
<body>
{{{body}}}

</body>
</html>
12 changes: 12 additions & 0 deletions assignments/hackyourtemperature/views/weatherShow.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Weather show</title>
</head>
<body>
<h1>{{data.name}} <b>{{data.main.temp_min}}</b></h1>
Copy link

Choose a reason for hiding this comment

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

I didn't test the API, but this doesn't seem like the correct field for showing the actual temperature. I think it should be data.main.temp.


</body>
</html>