Eric Whale

Fix css

...@@ -12,8 +12,8 @@ ...@@ -12,8 +12,8 @@
12 <link rel="manifest" href="%PUBLIC_URL%/manifest.json" /> 12 <link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
13 <title>Weather Chatbot</title> 13 <title>Weather Chatbot</title>
14 </head> 14 </head>
15 - <body> 15 + <body style="width: 100vw">
16 <noscript>You need to enable JavaScript to run this app.</noscript> 16 <noscript>You need to enable JavaScript to run this app.</noscript>
17 - <div id="root"></div> 17 + <div id="root" style="width: 100vw; margin: 0; padding: 0"></div>
18 </body> 18 </body>
19 </html> 19 </html>
......
...@@ -8,11 +8,13 @@ import Topbar from "./components/Topbar"; ...@@ -8,11 +8,13 @@ import Topbar from "./components/Topbar";
8 8
9 function App() { 9 function App() {
10 const token = sessionStorage.getItem("user-token"); 10 const token = sessionStorage.getItem("user-token");
11 + const [visited, setVisited] = useState(0);
11 const [weather, setWeather] = useState(); 12 const [weather, setWeather] = useState();
12 const [forecast, setForecast] = useState(); 13 const [forecast, setForecast] = useState();
13 const [air, setAir] = useState(); 14 const [air, setAir] = useState();
14 15
15 const handleData = async (e) => { 16 const handleData = async (e) => {
17 + setVisited(1);
16 setWeather(null); 18 setWeather(null);
17 setForecast(null); 19 setForecast(null);
18 setAir(null); 20 setAir(null);
...@@ -36,85 +38,95 @@ function App() { ...@@ -36,85 +38,95 @@ function App() {
36 return ( 38 return (
37 <div> 39 <div>
38 <Topbar /> 40 <Topbar />
39 - <div className="weather-buttons"> 41 + <div className="mainBox">
40 - <b>Types : </b> 42 + <div className="weather-buttons">
41 - <button id="weather" onClick={(e) => handleData(e)}> 43 + <b>Types {"-> "} </b>
42 - Weather 44 + <button id="weather" onClick={(e) => handleData(e)}>
43 - </button> 45 + Weather
44 - <button id="forecast" onClick={(e) => handleData(e)}> 46 + </button>
45 - Forecast 47 + <button id="forecast" onClick={(e) => handleData(e)}>
46 - </button> 48 + Forecast
47 - <button id="air" onClick={(e) => handleData(e)}> 49 + </button>
48 - Air Pollution 50 + <button id="air" onClick={(e) => handleData(e)}>
49 - </button> 51 + Air Pollution
50 - </div> 52 + </button>
53 + </div>
51 54
52 - <hr></hr> 55 + <hr></hr>
53 56
54 - {!weather ? ( 57 + {!visited && !weather && !forecast && !air ? (
55 - "" 58 + <h2>Click a button for weather service!</h2>
56 - ) : ( 59 + ) : (
57 - <div> 60 + ""
58 - <h2> 61 + )}
59 - {weather.meta.city} ({weather.meta.country}){" "}
60 - <small>UTC {weather.meta.timezone}</small>
61 - </h2>
62 - <h3>* {weather.description} *</h3>
63 - <p>
64 - 🌡 : {weather.temp.realCelcius} / feels like{" "}
65 - {weather.temp.feelCelcius} C
66 - </p>
67 - <p>🌬 : {weather.types.wind} m/s</p>
68 - <p>☁️ : {weather.types.clouds} %</p>
69 - <p>{weather.rain ? "☔️ : Yes" : "☔️ : No"}</p>
70 - <p>{weather.snow ? "❄️ : Yes" : "❄️ : No"}</p>
71 - </div>
72 - )}
73 62
74 - {!forecast ? ( 63 + {visited && !weather && !forecast && !air ? <h2>Loading...</h2> : ""}
75 - ""
76 - ) : (
77 - <div>
78 - <h2>
79 - {forecast.meta.city} ({forecast.meta.country}){" "}
80 - <small>UTC {forecast.meta.timezone}</small>
81 - </h2>
82 64
83 - {forecast.forecast.map((item, index) => ( 65 + {!weather ? (
84 - <div key={index} className="forecastItemBox"> 66 + ""
85 - <h3> 67 + ) : (
86 - {item.description} <small>{item.dateTime}</small> 68 + <div>
87 - </h3> 69 + <h2>
88 - <p> 70 + {weather.meta.city} ({weather.meta.country}){" "}
89 - Temperature : {item.temp.realCelcius} / feels like{" "} 71 + <small>UTC {weather.meta.timezone}</small>
90 - {item.temp.feelCelcius} 72 + </h2>
91 - </p> 73 + <h3>* {weather.description} *</h3>
92 - <p>Wind : {item.types.wind} m/s</p> 74 + <p>
93 - <p>Cloud : {item.types.clouds} %</p> 75 + 🌡 : {weather.temp.realCelcius} / feels like{" "}
94 - </div> 76 + {weather.temp.feelCelcius} C
95 - ))} 77 + </p>
96 - </div> 78 + <p>🌬 : {weather.types.wind} m/s</p>
97 - )} 79 + <p>☁️ : {weather.types.clouds} %</p>
80 + <p>{weather.rain ? "☔️ : Yes" : "☔️ : No"}</p>
81 + <p>{weather.snow ? "❄️ : Yes" : "❄️ : No"}</p>
82 + </div>
83 + )}
98 84
99 - {!air ? ( 85 + {!forecast ? (
100 - "" 86 + ""
101 - ) : ( 87 + ) : (
102 - <div> 88 + <div>
103 - <h2> 89 + <h2>
104 - {air.meta.state ? air.meta.state : ""} {air.meta.country} 90 + {forecast.meta.city} ({forecast.meta.country}){" "}
105 - </h2> 91 + <small>UTC {forecast.meta.timezone}</small>
106 - <p>CO : {air.airData.co} μg/m3</p> 92 + </h2>
107 - <p>NH3 : {air.airData.nh3} μg/m3</p> 93 +
108 - <p>NO : {air.airData.no} μg/m3</p> 94 + {forecast.forecast.map((item, index) => (
109 - <p>NO2 : {air.airData.no2} μg/m3</p> 95 + <div key={index} className="forecastItemBox">
110 - <p>O3 : {air.airData.o3} μg/m3</p> 96 + <h3>
111 - <p>SO2 : {air.airData.so2} μg/m3</p> 97 + {item.description} <small>{item.dateTime}</small>
112 - <p> 98 + </h3>
113 - {"pm2.5"} : {air.airData.pm2_5} μg/m3 99 + <p>
114 - </p> 100 + Temperature : {item.temp.realCelcius} / feels like{" "}
115 - <p>pm10 : {air.airData.pm10} μg/m3</p> 101 + {item.temp.feelCelcius}
116 - </div> 102 + </p>
117 - )} 103 + <p>Wind : {item.types.wind} m/s</p>
104 + <p>Cloud : {item.types.clouds} %</p>
105 + </div>
106 + ))}
107 + </div>
108 + )}
109 +
110 + {!air ? (
111 + ""
112 + ) : (
113 + <div>
114 + <h2>
115 + {air.meta.state ? air.meta.state : ""} {air.meta.country}
116 + </h2>
117 + <p>CO : {air.airData.co} μg/m3</p>
118 + <p>NH3 : {air.airData.nh3} μg/m3</p>
119 + <p>NO : {air.airData.no} μg/m3</p>
120 + <p>NO2 : {air.airData.no2} μg/m3</p>
121 + <p>O3 : {air.airData.o3} μg/m3</p>
122 + <p>SO2 : {air.airData.so2} μg/m3</p>
123 + <p>
124 + {"pm2.5"} : {air.airData.pm2_5} μg/m3
125 + </p>
126 + <p>pm10 : {air.airData.pm10} μg/m3</p>
127 + </div>
128 + )}
129 + </div>
118 130
119 <Bottombar /> 131 <Bottombar />
120 </div> 132 </div>
......
...@@ -10,6 +10,7 @@ function Topbar() { ...@@ -10,6 +10,7 @@ function Topbar() {
10 <Link to="/" className="logo"> 10 <Link to="/" className="logo">
11 <FcHome /> 11 <FcHome />
12 </Link> 12 </Link>
13 + <div className="title">🤖 Weather Chatbot</div>
13 <Link to="/settings" className="settings"> 14 <Link to="/settings" className="settings">
14 <AiFillSetting /> 15 <AiFillSetting />
15 </Link> 16 </Link>
......
...@@ -38,14 +38,16 @@ function Login() { ...@@ -38,14 +38,16 @@ function Login() {
38 }; 38 };
39 39
40 return ( 40 return (
41 - <div className="container"> 41 + <div className="mainBox">
42 <h1>Welcome back!</h1> 42 <h1>Welcome back!</h1>
43 <h2>Stay connected to weather*stories*friends</h2> 43 <h2>Stay connected to weather*stories*friends</h2>
44 44
45 <button>Login with Google</button> 45 <button>Login with Google</button>
46 + <br />
46 <button>Login with GitHub</button> 47 <button>Login with GitHub</button>
47 48
48 <br /> 49 <br />
50 + <br />
49 51
50 <form className="authForm" onSubmit={(e) => handleSubmit(e)}> 52 <form className="authForm" onSubmit={(e) => handleSubmit(e)}>
51 <label htmlFor="email"> 53 <label htmlFor="email">
...@@ -66,7 +68,7 @@ function Login() { ...@@ -66,7 +68,7 @@ function Login() {
66 id="password" 68 id="password"
67 /> 69 />
68 </label> 70 </label>
69 - <label htmlFor="submit"> 71 + <label className="submitBtn" htmlFor="submit">
70 <input type="submit" id="submit" /> 72 <input type="submit" id="submit" />
71 </label> 73 </label>
72 </form> 74 </form>
......
...@@ -4,6 +4,8 @@ import authService from "../service/auth"; ...@@ -4,6 +4,8 @@ import authService from "../service/auth";
4 // components 4 // components
5 import Topbar from "../components/Topbar"; 5 import Topbar from "../components/Topbar";
6 import Bottombar from "../components/Bottombar"; 6 import Bottombar from "../components/Bottombar";
7 +// styles
8 +import "../styles/layout.scss";
7 9
8 function Settings() { 10 function Settings() {
9 const token = sessionStorage.getItem("user-token"); 11 const token = sessionStorage.getItem("user-token");
...@@ -49,56 +51,63 @@ function Settings() { ...@@ -49,56 +51,63 @@ function Settings() {
49 return ( 51 return (
50 <div> 52 <div>
51 <Topbar /> 53 <Topbar />
52 - <h3>Edit Your information</h3> 54 + <div className="mainBox">
53 - <form className="authForm" onSubmit={(e) => handleSubmit(e)}> 55 + <h3>Edit Your information</h3>
54 - <label htmlFor="username"> 56 + <form className="authForm" onSubmit={(e) => handleSubmit(e)}>
55 - <input 57 + <label htmlFor="username">
56 - placeholder="username" 58 + <input
57 - onChange={(e) => onChange(e)} 59 + placeholder="username"
58 - value={userinfo.username} 60 + onChange={(e) => onChange(e)}
59 - type="text" 61 + value={userinfo.username}
60 - id="username" 62 + type="text"
61 - /> 63 + id="username"
62 - </label> 64 + />
63 - <label htmlFor="country"> 65 + </label>
64 - <input 66 + <label htmlFor="country">
65 - placeholder="Please use Alpha-2 Country Code" 67 + <input
66 - onChange={(e) => onChange(e)} 68 + placeholder="Please use Alpha-2 Country Code"
67 - value={userinfo.country.toUpperCase()} 69 + onChange={(e) => onChange(e)}
68 - type="text" 70 + value={userinfo.country.toUpperCase()}
69 - id="country" 71 + type="text"
70 - /> 72 + id="country"
71 - </label> 73 + />
72 - <label htmlFor="city"> 74 + </label>
73 - <input 75 + <label htmlFor="city">
74 - placeholder="City Name (lower case)" 76 + <input
75 - onChange={(e) => onChange(e)} 77 + placeholder="City Name (lower case)"
76 - value={userinfo.city.toLowerCase()} 78 + onChange={(e) => onChange(e)}
77 - type="text" 79 + value={userinfo.city.toLowerCase()}
78 - id="city" 80 + type="text"
79 - /> 81 + id="city"
80 - </label> 82 + />
81 - <label htmlFor="email"> 83 + </label>
82 - <input 84 + <label htmlFor="email">
83 - placeholder="Change email" 85 + <input
84 - onChange={(e) => onChange(e)} 86 + placeholder="Change email"
85 - value={userinfo.email} 87 + onChange={(e) => onChange(e)}
86 - type="email" 88 + value={userinfo.email}
87 - id="email" 89 + type="email"
88 - /> 90 + id="email"
89 - </label> 91 + />
90 - <label htmlFor="submit"> 92 + </label>
91 - <input type="submit" id="submit" /> 93 + <label className="submitBtn" htmlFor="submit">
92 - </label> 94 + <input type="submit" id="submit" />
93 - </form> 95 + </label>
96 + </form>
94 97
95 - <br /> 98 + <br />
96 99
97 - <div> 100 + <div>
98 - Want to logout?{" "} 101 + Want to logout?{" "}
99 - <button onClick={() => setLogoutSuccess("logout")}>Logout</button> 102 + <button
103 + className="logoutBtn"
104 + onClick={() => setLogoutSuccess("logout")}
105 + >
106 + Logout
107 + </button>
108 + </div>
109 + <Bottombar />
100 </div> 110 </div>
101 - <Bottombar />
102 </div> 111 </div>
103 ); 112 );
104 } 113 }
......
...@@ -36,14 +36,16 @@ function Signup() { ...@@ -36,14 +36,16 @@ function Signup() {
36 }; 36 };
37 37
38 return ( 38 return (
39 - <div className="container"> 39 + <div className="mainBox">
40 <h1>Welcome to WeatherAPP/twitter/Messanger!</h1> 40 <h1>Welcome to WeatherAPP/twitter/Messanger!</h1>
41 <h2>Stay connected to weather*stories*friends</h2> 41 <h2>Stay connected to weather*stories*friends</h2>
42 42
43 <button>Create account with Google</button> 43 <button>Create account with Google</button>
44 + <br />
44 <button>Create account with GitHub</button> 45 <button>Create account with GitHub</button>
45 46
46 <br /> 47 <br />
48 + <br />
47 49
48 <p> 50 <p>
49 <b>Country Code</b> and <b>City Name</b> is required for Weather 51 <b>Country Code</b> and <b>City Name</b> is required for Weather
...@@ -97,7 +99,7 @@ function Signup() { ...@@ -97,7 +99,7 @@ function Signup() {
97 /> 99 />
98 </label> 100 </label>
99 101
100 - <label htmlFor="submit"> 102 + <label className="submitBtn" htmlFor="submit">
101 <input type="submit" id="submit" /> 103 <input type="submit" id="submit" />
102 </label> 104 </label>
103 </form> 105 </form>
......
...@@ -7,7 +7,7 @@ function Tweet() { ...@@ -7,7 +7,7 @@ function Tweet() {
7 <div> 7 <div>
8 <Topbar /> 8 <Topbar />
9 9
10 - <div>tweet</div> 10 + <div className="mainBox">tweet</div>
11 11
12 <Bottombar /> 12 <Bottombar />
13 </div> 13 </div>
......
...@@ -6,7 +6,10 @@ ...@@ -6,7 +6,10 @@
6 align-items: center; 6 align-items: center;
7 text-align: center; 7 text-align: center;
8 padding: 10px; 8 padding: 10px;
9 - 9 + height: 9vh;
10 + position: fixed;
11 + font-size: 3rem;
12 + width: 100%;
10 a { 13 a {
11 width: 45%; 14 width: 45%;
12 height: 90%; 15 height: 90%;
...@@ -18,6 +21,7 @@ ...@@ -18,6 +21,7 @@
18 } 21 }
19 .logo { 22 .logo {
20 color: #008080; 23 color: #008080;
24 + font-size: 4rem;
21 } 25 }
22 26
23 * { 27 * {
...@@ -28,26 +32,31 @@ ...@@ -28,26 +32,31 @@
28 .topbar { 32 .topbar {
29 margin-bottom: 0.5rem; 33 margin-bottom: 0.5rem;
30 justify-content: space-between; 34 justify-content: space-between;
31 - border-bottom: 2px gray solid; 35 + border-bottom: 4px gray solid;
36 + top: 0;
32 a { 37 a {
33 - font-size: 2.9rem; 38 + height: 5rem;
34 - height: 3rem;
35 } 39 }
36 .logo { 40 .logo {
41 + font-size: 5rem;
37 text-align: left; 42 text-align: left;
38 } 43 }
39 .settings { 44 .settings {
45 + font-size: 4.5rem;
40 text-align: right; 46 text-align: right;
41 } 47 }
48 + .title {
49 + width: 40vw;
50 + }
42 } 51 }
43 .bottombar { 52 .bottombar {
44 margin-top: 0.5rem; 53 margin-top: 0.5rem;
45 - border-top: 2px gray solid; 54 + border-top: 4px gray solid;
46 - font-size: 1.5rem; 55 + bottom: 0;
47 - height: 2.8rem; 56 + height: 4rem;
48 .bottomBtn { 57 .bottomBtn {
49 - margin-right: 0.2rem; 58 + margin-right: 0.4rem;
50 - margin-left: 0.2rem; 59 + margin-left: 0.4rem;
51 border: 1px solid gray; 60 border: 1px solid gray;
52 border-radius: 3px; 61 border-radius: 3px;
53 box-shadow: 3px 3px 3px 0px gray; 62 box-shadow: 3px 3px 3px 0px gray;
......
1 +html {
2 + height: 100vh;
3 +}
1 * { 4 * {
2 margin: 0; 5 margin: 0;
3 padding: 0; 6 padding: 0;
4 - background-color: #FFDEAD; 7 + background-color: #ffdead;
5 } 8 }
6 9
7 .container { 10 .container {
8 display: flex; 11 display: flex;
9 flex-direction: column; 12 flex-direction: column;
10 - margin-left: 0.5rem; 13 +}
11 - margin-right: 0.5rem; 14 +
15 +.mainBox {
16 + min-height: 82vh;
17 + margin-top: 13vh;
18 + padding-left: 1rem;
19 + padding-right: 1rem;
20 + font-size: 2rem;
21 + * {
22 + font-size: 2rem;
23 + }
24 + h2 {
25 + font-size: 2.5rem;
26 + }
12 } 27 }
13 28
14 .authForm { 29 .authForm {
...@@ -25,12 +40,30 @@ ...@@ -25,12 +40,30 @@
25 } 40 }
26 } 41 }
27 42
43 +.submitBtn {
44 + width: 40%;
45 + color: green;
46 + border: green 2px solid;
47 + border-radius: 4px;
48 + input {
49 + background-color: green;
50 + }
51 +}
52 +
53 +.logoutBtn {
54 + width: 20%;
55 + border-radius: 4px;
56 + background-color: red;
57 +}
58 +
28 .weather-buttons { 59 .weather-buttons {
29 display: flex; 60 display: flex;
30 flex-direction: row; 61 flex-direction: row;
31 button { 62 button {
32 margin-left: 0.2rem; 63 margin-left: 0.2rem;
33 margin-right: 0.2rem; 64 margin-right: 0.2rem;
65 + padding: 0.2rem;
66 + border-radius: 6px;
34 } 67 }
35 } 68 }
36 69
......
1 -const bcrypt = require("bcryptjs");
2 -// handles "exception" inside of async express routes
3 -const asyncHandler = require("express-async-handler");
4 -const User = require("../models/userModel");
5 -const { jwtGenerator } = require("../config/jwt");
6 -
7 -// @desc Signup new user
8 -// @route POST /api/users
9 -// @access Public
10 -const signupUser = asyncHandler(async (req, res) => {
11 - const { username, country, city, email, password } = req.body;
12 - if (!username || !country || !city || !email || !password) {
13 - res.status(400);
14 - throw new Error("Please fill in all fields");
15 - }
16 -
17 - // Check if user already exists
18 - const userExists = await User.findOne({ email });
19 - if (userExists) {
20 - res.status(400);
21 - throw new Error("User with the email already exists");
22 - }
23 -
24 - // Hash password (bcrypt)
25 - const salt = await bcrypt.genSalt(10);
26 - const hashedPassword = await bcrypt.hash(password, salt);
27 -
28 - // Create/Build user
29 - const user = await User.create({
30 - username,
31 - country,
32 - city,
33 - email,
34 - password: hashedPassword,
35 - });
36 -
37 - // Send response
38 - if (user) {
39 - // 201: Resource successfully created
40 - res.status(201).json({
41 - _id: user.id,
42 - username: user.username,
43 - country: user.country,
44 - city: user.city,
45 - email: user.email,
46 - token: jwtGenerator(user._id),
47 - });
48 - } else {
49 - res.status(400);
50 - throw new Error("Invalid user data");
51 - }
52 -});
53 -
54 -// @desc Login user
55 -// @route POST /api/users/login
56 -// @access Public
57 -const loginUser = asyncHandler(async (req, res) => {
58 - const { email, password } = req.body;
59 -
60 - // Check email & password
61 - const userInDB = await User.findOne({ email });
62 - const validPassword = await bcrypt.compare(password, userInDB.password);
63 - if (userInDB && validPassword) {
64 - res.status(200).json({
65 - token: jwtGenerator(userInDB._id),
66 - });
67 - } else {
68 - res.status(400);
69 - throw new Error("Invalid credentials");
70 - }
71 -});
72 -
73 -// @desc Get all users
74 -// @route GET /api/users/all
75 -// @access Public
76 -const getAllusers = asyncHandler(async (req, res) => {
77 - const users = await User.find()
78 - .select("-password")
79 - .select("-createdAt")
80 - .select("-email");
81 -
82 - res.status(200).json(users);
83 -});
84 -
85 -// @desc Get user
86 -// @route GET /api/users/self
87 -// @access Private
88 -const getSelf = asyncHandler(async (req, res) => {
89 - res.status(200).json(req.user);
90 -});
91 -
92 -// @desc Edit user
93 -// @route PUT /api/users/edit
94 -// @access Private
95 -const editUser = asyncHandler(async (req, res) => {
96 - const {username, country, city, email} = req.body;
97 - console.log(username);
98 - res.json({});
99 -});
100 -
101 -module.exports = {
102 - signupUser,
103 - loginUser,
104 - getAllusers,
105 - getSelf,
106 - editUser,
107 -};