Showing
10 changed files
with
90 additions
and
129 deletions
... | @@ -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,8 +38,9 @@ function App() { | ... | @@ -36,8 +38,9 @@ function App() { |
36 | return ( | 38 | return ( |
37 | <div> | 39 | <div> |
38 | <Topbar /> | 40 | <Topbar /> |
41 | + <div className="mainBox"> | ||
39 | <div className="weather-buttons"> | 42 | <div className="weather-buttons"> |
40 | - <b>Types : </b> | 43 | + <b>Types {"-> "} </b> |
41 | <button id="weather" onClick={(e) => handleData(e)}> | 44 | <button id="weather" onClick={(e) => handleData(e)}> |
42 | Weather | 45 | Weather |
43 | </button> | 46 | </button> |
... | @@ -51,6 +54,14 @@ function App() { | ... | @@ -51,6 +54,14 @@ function App() { |
51 | 54 | ||
52 | <hr></hr> | 55 | <hr></hr> |
53 | 56 | ||
57 | + {!visited && !weather && !forecast && !air ? ( | ||
58 | + <h2>Click a button for weather service!</h2> | ||
59 | + ) : ( | ||
60 | + "" | ||
61 | + )} | ||
62 | + | ||
63 | + {visited && !weather && !forecast && !air ? <h2>Loading...</h2> : ""} | ||
64 | + | ||
54 | {!weather ? ( | 65 | {!weather ? ( |
55 | "" | 66 | "" |
56 | ) : ( | 67 | ) : ( |
... | @@ -115,6 +126,7 @@ function App() { | ... | @@ -115,6 +126,7 @@ function App() { |
115 | <p>pm10 : {air.airData.pm10} μg/m3</p> | 126 | <p>pm10 : {air.airData.pm10} μg/m3</p> |
116 | </div> | 127 | </div> |
117 | )} | 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,6 +51,7 @@ function Settings() { | ... | @@ -49,6 +51,7 @@ function Settings() { |
49 | return ( | 51 | return ( |
50 | <div> | 52 | <div> |
51 | <Topbar /> | 53 | <Topbar /> |
54 | + <div className="mainBox"> | ||
52 | <h3>Edit Your information</h3> | 55 | <h3>Edit Your information</h3> |
53 | <form className="authForm" onSubmit={(e) => handleSubmit(e)}> | 56 | <form className="authForm" onSubmit={(e) => handleSubmit(e)}> |
54 | <label htmlFor="username"> | 57 | <label htmlFor="username"> |
... | @@ -87,7 +90,7 @@ function Settings() { | ... | @@ -87,7 +90,7 @@ function Settings() { |
87 | id="email" | 90 | id="email" |
88 | /> | 91 | /> |
89 | </label> | 92 | </label> |
90 | - <label htmlFor="submit"> | 93 | + <label className="submitBtn" htmlFor="submit"> |
91 | <input type="submit" id="submit" /> | 94 | <input type="submit" id="submit" /> |
92 | </label> | 95 | </label> |
93 | </form> | 96 | </form> |
... | @@ -96,10 +99,16 @@ function Settings() { | ... | @@ -96,10 +99,16 @@ function Settings() { |
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> | ||
100 | </div> | 108 | </div> |
101 | <Bottombar /> | 109 | <Bottombar /> |
102 | </div> | 110 | </div> |
111 | + </div> | ||
103 | ); | 112 | ); |
104 | } | 113 | } |
105 | 114 | ... | ... |
... | @@ -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> | ... | ... |
... | @@ -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 | ... | ... |
server/'
deleted
100644 → 0
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 | -}; |
-
Please register or login to post a comment