diff --git a/package-lock.json b/package-lock.json index 26e3ebf..82c4f4b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ "@testing-library/user-event": "^13.5.0", "axios": "^1.3.5", "formik": "^2.2.9", + "jsonwebtoken": "^9.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hot-toast": "^2.4.0", @@ -5562,6 +5563,11 @@ "node-int64": "^0.4.0" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/buffer-from": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", @@ -6792,6 +6798,14 @@ "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -11726,6 +11740,21 @@ "node": ">=0.10.0" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.0.tgz", + "integrity": "sha512-tuGfYXxkQGDPnLJ7SibiQgVgeDgfbPq2k2ICcbgqW8WxWLBAxKQM/ZCu/IT8SOSwmaYl4dpTFCW5xZv7YbbWUw==", + "dependencies": { + "jws": "^3.2.2", + "lodash": "^4.17.21", + "ms": "^2.1.1", + "semver": "^7.3.8" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.3.tgz", @@ -11738,6 +11767,25 @@ "node": ">=4.0" } }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", diff --git a/package.json b/package.json index ee9ac18..0fdb170 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "@testing-library/user-event": "^13.5.0", "axios": "^1.3.5", "formik": "^2.2.9", + "jsonwebtoken": "^9.0.0", "react": "^18.2.0", "react-dom": "^18.2.0", "react-hot-toast": "^2.4.0", diff --git a/src/App.js b/src/App.js index 6b7386c..a7afb32 100644 --- a/src/App.js +++ b/src/App.js @@ -1,18 +1,26 @@ import { HomePage, PostForm, NotFoundPage } from "./pages/index"; -import { Routes, Route } from "react-router-dom"; +import { Routes, Route, Navigate } from "react-router-dom"; import { PostProvider } from "./context/postContext"; import { Toaster } from "react-hot-toast"; +import Signup from './components/signup'; +import Login from './components/Login'; + function App() { + + const user = localStorage.getItem("token") return (
- } /> + {user && }/>} + }/> + }/> } /> } /> } /> + }/> diff --git a/src/components/Login/index.jsx b/src/components/Login/index.jsx new file mode 100644 index 0000000..ae02cbc --- /dev/null +++ b/src/components/Login/index.jsx @@ -0,0 +1,85 @@ +import { useState } from "react"; +import styles from "./styles.module.css"; +import { Link } from "react-router-dom"; +import axios from 'axios' + +const Signup = () => { + const [data, setData] = useState({ + email: "", + password: "", + }); + + + const [error, setError] = useState("") + + const handleChange = ({ currentTarget: input }) => { + setData({ ...data, [input.name]: input.value }); + }; + + const handleSubmit =async (e) => { + e.preventDefault(); + try { + const url = "http://localhost:4000/api/auth/signin"; + const {data:res} = await axios.post(url,data); + localStorage.setItem("token", res.data); + window.location= "/" + } catch (error) { + if(error.response && + error.response.status >=400 && + error.response.status <=500 + ){ + setError(error.response.data.message) + } + + } + + } + + return ( +
+
+
+
+

Login to Your Account

+ + + + {error &&
{error}
} + +
+
+

New Here?

+ + + +
+
+ +
+ +
+ ); +}; + +export default Signup; \ No newline at end of file diff --git a/src/components/Login/styles.module.css b/src/components/Login/styles.module.css new file mode 100644 index 0000000..c1a1ff1 --- /dev/null +++ b/src/components/Login/styles.module.css @@ -0,0 +1,98 @@ +.login_container { + width: 100%; + min-height: 100vh; + background-color: #f5f5f5; + display: flex; + align-items: center; + justify-content: center; +} + +.login_form_container { + width: 900px; + height: 500px; + display: flex; + border-radius: 10px; + box-shadow: 0px 3px 3px -2px rgb(0 0 0 / 20%), + 0px 3px 4px 0px rgb(0 0 0 / 14%), 0px 1px 8px 0px rgb(0 0 0 / 12%); +} + +.left { + flex: 2; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: white; + border-top-left-radius: 10px; + border-bottom-left-radius: 10px; +} + +.form_container { + display: flex; + flex-direction: column; + align-items: center; +} + +.form_container h1 { + font-size: 40px; + margin-top: 0; +} + +.input { + outline: none; + border: none; + width: 370px; + padding: 15px; + border-radius: 10px; + background-color: #edf5f3; + margin: 5px 0; + font-size: 14px; +} + +.error_msg { + width: 370px; + padding: 15px; + margin: 5px 0; + font-size: 14px; + background-color: #f34646; + color: white; + border-radius: 5px; + text-align: center; +} + +.right { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: #3bb19b; + border-top-right-radius: 10px; + border-bottom-right-radius: 10px; +} + +.right h1 { + margin-top: 0; + color: white; + font-size: 40px; + align-self: center; +} + +.white_btn, +.green_btn { + border: none; + outline: none; + padding: 12px 0; + background-color: white; + border-radius: 20px; + width: 180px; + font-weight: bold; + font-size: 14px; + cursor: pointer; +} + +.green_btn { + background-color: #3bb19b; + color: white; + margin: 10px; +} \ No newline at end of file diff --git a/src/components/Main/index.jsx b/src/components/Main/index.jsx new file mode 100644 index 0000000..113a2a4 --- /dev/null +++ b/src/components/Main/index.jsx @@ -0,0 +1,24 @@ +import styles from './style.module.css'; + + +const Main = () =>{ + + const handleLogout = ()=> { + localStorage.removeItem("token"); + window.location.reload(); +} + +return( +
+ +
+); + + +}; +export default Main; \ No newline at end of file diff --git a/src/components/Main/style.module.css b/src/components/Main/style.module.css new file mode 100644 index 0000000..3cb8dac --- /dev/null +++ b/src/components/Main/style.module.css @@ -0,0 +1,27 @@ +.navbar { + width: 100%; + height: 70px; + background-color: #3bb19b; + display: flex; + align-items: center; + justify-content: space-between; +} + +.navbar h1 { + color: white; + font-size: 25px; + margin-left: 20px; +} + +.white_btn { + border: none; + outline: none; + padding: 12px 0; + background-color: white; + border-radius: 20px; + width: 120px; + font-weight: bold; + font-size: 14px; + cursor: pointer; + margin-right: 20px; +} \ No newline at end of file diff --git a/src/components/signup/index.jsx b/src/components/signup/index.jsx new file mode 100644 index 0000000..e2924b8 --- /dev/null +++ b/src/components/signup/index.jsx @@ -0,0 +1,93 @@ +import { useState } from "react"; +import styles from "./styles.module.css"; +import { Link, useNavigate } from "react-router-dom"; +import axios from 'axios' + +const Signup = () => { + const [data, setData] = useState({ + username: "", + email: "", + password: "", + }); + const [error, setError] = useState("") + const navigate= useNavigate(); + + const handleChange = ({ currentTarget: input }) => { + setData({ ...data, [input.name]: input.value }); + }; + + const handleSubmit =async (e) => { + e.preventDefault(); + try { + const url = "http://localhost:4000/api/auth/signup"; + const {data:res} = await axios.post(url,data); + navigate("/login") + console.log(res.message) + } catch (error) { + if(error.response && + error.response.status >=400 && + error.response.status <=500 + ){ + setError(error.response.data.message) + } + + } + + } + + return ( +
+
+
+

Welcome Back

+ + + +
+
+
+
+

Create Account

+ + + + + + {error &&
{error}
} + +
+
+
+ ); +}; + +export default Signup; diff --git a/src/components/signup/styles.module.css b/src/components/signup/styles.module.css new file mode 100644 index 0000000..15c6aa7 --- /dev/null +++ b/src/components/signup/styles.module.css @@ -0,0 +1,98 @@ +.signup_container { + width: 100%; + min-height: 100vh; + background-color: #f5f5f5; + display: flex; + align-items: center; + justify-content: center; +} + +.signup_form_container { + width: 900px; + height: 500px; + display: flex; + border-radius: 10px; + box-shadow: 0px 3px 3px -2px rgb(0 0 0 / 20%), + 0px 3px 4px 0px rgb(0 0 0 / 14%), 0px 1px 8px 0px rgb(0 0 0 / 12%); +} + +.left { + flex: 1; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: #3bb19b; + border-top-left-radius: 10px; + border-bottom-left-radius: 10px; +} + +.left h1 { + margin-top: 0; + color: white; + font-size: 35px; + align-self: center; +} + +.right { + flex: 2; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + background-color: white; + border-top-right-radius: 10px; + border-bottom-right-radius: 10px; +} + +.form_container { + display: flex; + flex-direction: column; + align-items: center; +} + +.form_container h1 { + font-size: 40px; + margin-top: 0; +} + +.input { + outline: none; + border: none; + width: 370px; + padding: 15px; + border-radius: 10px; + background-color: #edf5f3; + margin: 5px 0; + font-size: 14px; +} + +.error_msg { + width: 370px; + padding: 15px; + margin: 5px 0; + font-size: 14px; + background-color: #f34646; + color: white; + border-radius: 5px; + text-align: center; +} + +.white_btn, +.green_btn { + border: none; + outline: none; + padding: 12px 0; + background-color: rgb(102, 115, 212); + border-radius: 20px; + width: 180px; + font-weight: bold; + font-size: 14px; + cursor: pointer; +} + +.green_btn { + background-color: #3bb19b; + color: white; + margin: 10px; +} \ No newline at end of file diff --git a/src/pages/HomePage.js b/src/pages/HomePage.js index c343023..0ed75f4 100644 --- a/src/pages/HomePage.js +++ b/src/pages/HomePage.js @@ -2,7 +2,12 @@ import { usePosts } from "../context/postContext"; import {VscEmptyWindow} from 'react-icons/vsc' import { Link } from "react-router-dom"; import { PostCard } from "../components/PostCard"; + export function HomePage() { + const handleLogout = ()=> { + localStorage.removeItem("token"); + window.location.reload(); +} const { posts } = usePosts() @@ -15,13 +20,19 @@ export function HomePage() { return (
- + +

Post ({posts.length})

Create new Post
-
+
{posts.map(post => ( ))}