From f61159eca45fe3aa29137e5b11b5478264d941f4 Mon Sep 17 00:00:00 2001 From: edwin6666 Date: Mon, 26 Jun 2023 10:39:48 -0400 Subject: [PATCH 1/4] Fix: route public --- src/components/RequiresAuth.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/RequiresAuth.jsx b/src/components/RequiresAuth.jsx index 03cab63..40822f7 100644 --- a/src/components/RequiresAuth.jsx +++ b/src/components/RequiresAuth.jsx @@ -7,7 +7,7 @@ const RequiresAuth = ( {allowedRoles } ) => { const location = useLocation() return ( - auth?.roles?.find(role => allowedRoles?.includes(role.name)) ? : + auth?.roles?.find(role => allowedRoles?.includes(role.name)) ? : ) } From c6817970a6cd32ed46d5e332c532965be928eebb Mon Sep 17 00:00:00 2001 From: edwin6666 Date: Fri, 30 Jun 2023 16:23:59 -0400 Subject: [PATCH 2/4] Feat Navbar,necessary paths and style --- src/App.js | 29 +++++--- src/components/Main/index.jsx | 22 ------ src/components/Main/style.module.css | 27 ------- src/components/Navbar/Navbar.jsx | 56 ++++++++++++++ src/components/PostCard.jsx | 39 ++++++---- src/components/PostCardUser.jsx | 32 ++++++++ src/index.js | 4 +- src/pages/Contact.js | 106 +++++++++++++++++++++++++++ src/pages/HomePage.js | 22 +----- src/pages/HomePageUser.js | 29 ++++++++ src/pages/PostForm.js | 11 ++- 11 files changed, 279 insertions(+), 98 deletions(-) delete mode 100644 src/components/Main/index.jsx delete mode 100644 src/components/Main/style.module.css create mode 100644 src/components/Navbar/Navbar.jsx create mode 100644 src/components/PostCardUser.jsx create mode 100644 src/pages/Contact.js create mode 100644 src/pages/HomePageUser.js diff --git a/src/App.js b/src/App.js index 7d5d882..92ca0d6 100644 --- a/src/App.js +++ b/src/App.js @@ -5,18 +5,31 @@ import { Toaster } from "react-hot-toast"; import Signup from './components/Signup'; import Login from './components/Login'; import RequiresAuth from "./components/RequiresAuth"; - +import { HomePageUser } from "./pages/HomePageUser"; +import Navbar from "./components/Navbar/Navbar"; +import { useLocation } from "react-router-dom"; +import ContactForm from "./pages/Contact"; function App() { - + const location = useLocation(); + const isLoginPage = location.pathname === '/login'; return ( - +
- + {/* Public routes */} }/> }/> + } /> + } /> {/* Private routes */} }> @@ -25,19 +38,13 @@ function App() { } /> - - }> - - - - {/* Catch all */} } /> - +
); } diff --git a/src/components/Main/index.jsx b/src/components/Main/index.jsx deleted file mode 100644 index a6efd9e..0000000 --- a/src/components/Main/index.jsx +++ /dev/null @@ -1,22 +0,0 @@ -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 deleted file mode 100644 index 3cb8dac..0000000 --- a/src/components/Main/style.module.css +++ /dev/null @@ -1,27 +0,0 @@ -.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/Navbar/Navbar.jsx b/src/components/Navbar/Navbar.jsx new file mode 100644 index 0000000..4a84c5c --- /dev/null +++ b/src/components/Navbar/Navbar.jsx @@ -0,0 +1,56 @@ +import React, { useState } from 'react'; + + const Navbar = () => { + const handleLogout = ()=> { + localStorage.removeItem("token"); + window.location.reload("/login"); + } + const [open, setOpen] = useState(true); + + const toggleMenu = () => { + setOpen(!open); + }; + + + + + + return ( + +
+
+
+
+ TechTalk News + +
+ +
+
+
+ + ); +}; + +export default Navbar; \ No newline at end of file diff --git a/src/components/PostCard.jsx b/src/components/PostCard.jsx index df330f9..c24e14d 100644 --- a/src/components/PostCard.jsx +++ b/src/components/PostCard.jsx @@ -43,11 +43,22 @@ export function PostCard({ post }) { }; return ( -
-
+ +
+
+
+ Alex +
+

TechTalk

+

{post.createdAt}

+
+
+
+ + + +
+
-
-

{post.title}

- -
-

{post.description}

-
- {post.image && imagen proporcionada por el Moderador} -
+ {post.image && imagen } +
+ +

{post.title}

+

{post.description}

- ); -} + +); +}; diff --git a/src/components/PostCardUser.jsx b/src/components/PostCardUser.jsx new file mode 100644 index 0000000..8130285 --- /dev/null +++ b/src/components/PostCardUser.jsx @@ -0,0 +1,32 @@ + + + +export function PostCardUser({ post }) { + + return ( + +
+
+
+ Alex +
+

TechTalk

+

{post.createdAt}

+
+
+
+ + + +
+
+ {post.image && imagen } +
+ +

{post.title}

+

{post.description}

+
+
+ +); +}; \ No newline at end of file diff --git a/src/index.js b/src/index.js index 799f591..81592b2 100644 --- a/src/index.js +++ b/src/index.js @@ -19,7 +19,5 @@ root.render( ); -// 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(); diff --git a/src/pages/Contact.js b/src/pages/Contact.js new file mode 100644 index 0000000..49f1a2e --- /dev/null +++ b/src/pages/Contact.js @@ -0,0 +1,106 @@ +import { useState } from 'react'; + +const ContactForm = () => { + const [formValues, setFormValues] = useState({ + name: '', + email: '', + message: '' + }); + + const handleChange = (e) => { + setFormValues({ + ...formValues, + [e.target.name]: e.target.value + }); + }; + + const handleSubmit = (e) => { + e.preventDefault(); + const formData = new FormData(e.target); + + fetch('https://api.web3forms.com/submit', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Accept: 'application/json' + }, + body: JSON.stringify(Object.fromEntries(formData)) + }) + .then(async (response) => { + let json = await response.json(); + if (response.status === 200) { + console.log(json.message); + } else { + console.log(response); + } + }) + .catch((error) => { + console.log(error); + }); + + setFormValues({ + name: '', + email: '', + message: '' + }); + }; + + return ( +
+
+

Contact us

+

Email us at help@techtalk12.com or message us here:

+ +
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +
+
+
+ ); +}; + +export default ContactForm; \ No newline at end of file diff --git a/src/pages/HomePage.js b/src/pages/HomePage.js index 0ed75f4..8f9bf0b 100644 --- a/src/pages/HomePage.js +++ b/src/pages/HomePage.js @@ -1,13 +1,10 @@ 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() @@ -19,24 +16,11 @@ export function HomePage() { ) return ( -
- - -
-

Post ({posts.length})

- Create new Post -
-
{posts.map(post => ( ))}
-
+ ); } diff --git a/src/pages/HomePageUser.js b/src/pages/HomePageUser.js new file mode 100644 index 0000000..9e90c75 --- /dev/null +++ b/src/pages/HomePageUser.js @@ -0,0 +1,29 @@ +import { usePosts } from "../context/postContext"; +import {VscEmptyWindow} from 'react-icons/vsc' + +import { PostCardUser } from "../components/PostCardUser"; + +export function HomePageUser() { + + const { posts } = usePosts() + + if (posts.length === 0 ) + return (
+ +

there are not posts

+
+ ) + + return ( + + + + +
+ {posts.map(post => ( + + ))} +
+ + ); +} \ No newline at end of file diff --git a/src/pages/PostForm.js b/src/pages/PostForm.js index 1574875..c1e9690 100644 --- a/src/pages/PostForm.js +++ b/src/pages/PostForm.js @@ -107,7 +107,16 @@ export function PostForm() { className="bg-indigo-600 hover:bg-indigo-500 px-4 py-2 rounded mt-2 text-white focus:outline-none disabled:bg-indigo-400" disable={isSubmitting} > - {isSubmitting ? 'Loading' : 'Save'} + {isSubmitting ? : 'Save'} )} From 7f38255d5d0beabef7b539b2e96c22406d9d94e0 Mon Sep 17 00:00:00 2001 From: edwin6666 Date: Fri, 30 Jun 2023 16:30:15 -0400 Subject: [PATCH 3/4] Fix: Route Contact in menu --- src/components/Navbar/Navbar.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/Navbar/Navbar.jsx b/src/components/Navbar/Navbar.jsx index 4a84c5c..77a83e7 100644 --- a/src/components/Navbar/Navbar.jsx +++ b/src/components/Navbar/Navbar.jsx @@ -36,7 +36,7 @@ import React, { useState } from 'react'; Home Create Post Admin Page - Contact + Contact
setOpen(false)}>
); } diff --git a/src/api/posts.js b/src/api/posts.js index d68177f..428e75b 100644 --- a/src/api/posts.js +++ b/src/api/posts.js @@ -1,28 +1,37 @@ -import axios from 'axios'; - -export const getPostsRequest = async () => await axios.get('http://localhost:4000/api/posts',{ - -}) - -export const createPostRequest = async (post) => { - const token = localStorage.getItem('auth') - const form = new FormData() - - for (let key in post){ - form.append(key, post[key]) - } - - return await axios.post('http://localhost:4000/api/posts', form, { - headers: { - "Content-Type": "multipart/form-data", - // eslint-disable-next-line no-template-curly-in-string - 'Authorization': `Bearer ${token}` - } - }); -} - -export const deletePostRequest = async id => await axios.delete("http://localhost:4000/api/posts/" + id) - -export const getPostRequest = async id => await axios.get("http://localhost:4000/api/posts/" + id) - -export const updatePostRequest = async (id, newFields) => await axios.put(`http://localhost:4000/api/posts/${id}`, newFields) \ No newline at end of file +import axios from "axios"; + +export const getPostsRequest = async () => + await axios.get("http://localhost:4000/api/posts", {}); + +export const createPostRequest = async (post, token) => { + const form = new FormData(); + + for (let key in post) { + form.append(key, post[key]); + } + + return await axios.post("http://localhost:4000/api/posts", form, { + headers: { + "Content-Type": "multipart/form-data", + // eslint-disable-next-line no-template-curly-in-string + Authorization: `Bearer ${token}`, + }, + }); +}; + +export const deletePostRequest = async (id, token) => + await axios.delete("http://localhost:4000/api/posts/" + id, { + headers: { + Authorization: `Bearer ${token}`, + }, + }); + +export const getPostRequest = async (id) => + await axios.get("http://localhost:4000/api/posts/" + id); + +export const updatePostRequest = async (id, newFields, token) => + await axios.put(`http://localhost:4000/api/posts/${id}`, newFields, { + headers: { + Authorization: `Bearer ${token}`, + }, + }); diff --git a/src/components/Login/index.jsx b/src/components/Login/index.jsx index 2c30bfc..44278b9 100644 --- a/src/components/Login/index.jsx +++ b/src/components/Login/index.jsx @@ -1,20 +1,20 @@ import { useState } from "react"; import { useNavigate, useLocation } from "react-router-dom"; import useAuth from "../../hooks/useAuth"; -import axios from 'axios' +import axios from "axios"; const Signin = () => { const [data, setData] = useState({ email: "", password: "", }); - const [error, setError] = useState("") + const [error, setError] = useState(""); - const { setAuth } = useAuth() + const { setAuth } = useAuth(); - const location = useLocation() - const navigate = useNavigate() - const from = location.state?.from?.pathname || "/" + const location = useLocation(); + const navigate = useNavigate(); + const from = location.state?.from?.pathname || "/"; const handleChange = ({ currentTarget: input }) => { setData({ ...data, [input.name]: input.value }); @@ -23,97 +23,138 @@ const Signin = () => { const handleSubmit = async (e) => { e.preventDefault(); try { - const url = "http://localhost:4000/api/auth/signin"; - const {data:res} = await axios.post(url, data); - const roles = res?.roles - const token = res?.token - setAuth({roles, token}) - console.log(roles) - navigate(from, {replace: true}) - + const url = "http://localhost:4000/api/auth/signin"; + const { data: res } = await axios.post(url, data); + const roles = res?.roles; + const token = res?.token; + setAuth({ roles, token }); + + console.log(roles); + navigate(from, { replace: true }); } catch (error) { - if(error.response && - error.response.status >=400 && - error.response.status <=500 - ){ - setError(error.response.data.message) - } - + if ( + error.response && + error.response.status >= 400 && + error.response.status <= 500 + ) { + setError(error.response.data.message); + } } - - } + }; return (
-
-
-
-
-

TechTalk News

-

Welcome to TechTalk, the go-to social network for technology and news enthusiasts! Here, you can connect with a passionate community that shares your interests and discover the latest trends in the digital world.

-
-
-
+
+
+
+
+

TechTalk News

+

+ Welcome to TechTalk, the go-to social network for technology and + news enthusiasts! Here, you can connect with a passionate + community that shares your interests and discover the latest + trends in the digital world. +

+
+
+
-
-
-
-

Techtalk

-

Sign in to access your account

-
+
+
+
+

+ TechTalk{" "} +

+

+ Sign in to access your account +

+
-
-
-
- - -
+
+ +
+ + +
-
-
- - Forgot password? -
+
+
+ + + Forgot password? + +
- -
+ +
-
- {error &&
{error}
} - - -
- +
+ {error && ( +
+ {error} +
+ )} -

Don't have an account yet? Sign up.

-
-
-
-
-
+ +
+ -); -} -export default Signin; \ No newline at end of file +

+ Don't have an account yet?{" "} + + Sign up + + . +

+
+
+
+
+
+ ); +}; +export default Signin; diff --git a/src/components/Navbar/Navbar.jsx b/src/components/Navbar/Navbar.jsx index 77a83e7..827680d 100644 --- a/src/components/Navbar/Navbar.jsx +++ b/src/components/Navbar/Navbar.jsx @@ -1,4 +1,9 @@ import React, { useState } from 'react'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faSignOutAlt } from '@fortawesome/free-solid-svg-icons'; + + + const Navbar = () => { const handleLogout = ()=> { @@ -21,7 +26,7 @@ import React, { useState } from 'react';
- TechTalk News + TechTalk News diff --git a/src/components/PostCard.jsx b/src/components/PostCard.jsx index c24e14d..3eaf805 100644 --- a/src/components/PostCard.jsx +++ b/src/components/PostCard.jsx @@ -43,41 +43,45 @@ export function PostCard({ post }) { }; return ( -
- Alex + Alex
-

TechTalk

-

{post.createdAt}

+

+ TechTalk +

+

+ {post.createdAt} +

- - - -
-
- + {" "} - {post.image && imagen } +
+
+ + {post.image && imagen }
-

{post.title}

{post.description}

- -); -}; + ); +} diff --git a/src/context/AuthProvider.js b/src/context/AuthProvider.js index 73b881e..9388742 100644 --- a/src/context/AuthProvider.js +++ b/src/context/AuthProvider.js @@ -3,15 +3,14 @@ import { createContext, useState } from "react"; const AuthContext = createContext({}); -export const AuthProvider = ({children}) => { - const [auth, setAuth] = useState({}) +export const AuthProvider = ({ children }) => { + const [auth, setAuth] = useState({}); - return ( - - {children} - - ) -} + return ( + + {children} + + ); +}; - -export default AuthContext \ No newline at end of file +export default AuthContext; diff --git a/src/context/postContext.js b/src/context/postContext.js index dc37877..c8d7d45 100644 --- a/src/context/postContext.js +++ b/src/context/postContext.js @@ -6,6 +6,7 @@ import { getPostRequest, updatePostRequest, } from "../api/posts"; +import useAuth from "../hooks/useAuth"; export const postContext = createContext(); @@ -16,6 +17,7 @@ export const usePosts = () => { export const PostProvider = ({ children }) => { const [posts, setPosts] = useState([]); + const {auth } = useAuth() useEffect(() => { (async () => { @@ -26,7 +28,7 @@ export const PostProvider = ({ children }) => { const createPost = async (post) => { try { - const res = await createPostRequest(post); + const res = await createPostRequest(post, auth.token); setPosts([...posts, res.data]); } catch (error) { console.log(error) @@ -34,7 +36,7 @@ export const PostProvider = ({ children }) => { }; const deletePost = async (id) => { - await deletePostRequest(id); + await deletePostRequest(id, auth.token); setPosts(posts.filter((post) => post._id !== id)); }; @@ -49,7 +51,7 @@ export const PostProvider = ({ children }) => { const updatePost = async (id, post) => { - const res = await updatePostRequest(id, post); + const res = await updatePostRequest(id, post, auth.token); setPosts(posts.map((post) => (post.id === id ? res.data : post))); }; diff --git a/src/pages/Contact.js b/src/pages/Contact.js index 49f1a2e..0d308d0 100644 --- a/src/pages/Contact.js +++ b/src/pages/Contact.js @@ -1,16 +1,16 @@ -import { useState } from 'react'; +import { useState } from "react"; const ContactForm = () => { const [formValues, setFormValues] = useState({ - name: '', - email: '', - message: '' + name: "", + email: "", + message: "", }); const handleChange = (e) => { setFormValues({ ...formValues, - [e.target.name]: e.target.value + [e.target.name]: e.target.value, }); }; @@ -18,13 +18,13 @@ const ContactForm = () => { e.preventDefault(); const formData = new FormData(e.target); - fetch('https://api.web3forms.com/submit', { - method: 'POST', + fetch("https://api.web3forms.com/submit", { + method: "POST", headers: { - 'Content-Type': 'application/json', - Accept: 'application/json' + "Content-Type": "application/json", + Accept: "application/json", }, - body: JSON.stringify(Object.fromEntries(formData)) + body: JSON.stringify(Object.fromEntries(formData)), }) .then(async (response) => { let json = await response.json(); @@ -39,9 +39,9 @@ const ContactForm = () => { }); setFormValues({ - name: '', - email: '', - message: '' + name: "", + email: "", + message: "", }); }; @@ -49,10 +49,20 @@ const ContactForm = () => {

Contact us

-

Email us at help@techtalk12.com or message us here:

+

+ Email us at help@techtalk12.com or message us here: +

-
- + +
{
-
@@ -103,4 +116,4 @@ const ContactForm = () => { ); }; -export default ContactForm; \ No newline at end of file +export default ContactForm; diff --git a/yarn.lock b/yarn.lock index 93aac5a..82f7395 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1308,6 +1308,39 @@ resolved "https://registry.npmjs.org/@eslint/js/-/js-8.43.0.tgz" integrity sha512-s2UHCoiXfxMvmfzqoN+vrQ84ahUSYde9qNO1MdxmoEhyHWsfmwOpFlwYV+ePJEVc7gFnATGUi376WowX1N7tFg== +"@fortawesome/fontawesome-common-types@6.4.0": + version "6.4.0" + resolved "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.4.0.tgz" + integrity sha512-HNii132xfomg5QVZw0HwXXpN22s7VBHQBv9CeOu9tfJnhsWQNd2lmTNi8CSrnw5B+5YOmzu1UoPAyxaXsJ6RgQ== + +"@fortawesome/fontawesome-svg-core@^6.4.0", "@fortawesome/fontawesome-svg-core@~1 || ~6": + version "6.4.0" + resolved "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.4.0.tgz" + integrity sha512-Bertv8xOiVELz5raB2FlXDPKt+m94MQ3JgDfsVbrqNpLU9+UE2E18GKjLKw+d3XbeYPqg1pzyQKGsrzbw+pPaw== + dependencies: + "@fortawesome/fontawesome-common-types" "6.4.0" + +"@fortawesome/free-brands-svg-icons@^6.4.0": + version "6.4.0" + resolved "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.4.0.tgz" + integrity sha512-qvxTCo0FQ5k2N+VCXb/PZQ+QMhqRVM4OORiO6MXdG6bKolIojGU/srQ1ptvKk0JTbRgaJOfL2qMqGvBEZG7Z6g== + dependencies: + "@fortawesome/fontawesome-common-types" "6.4.0" + +"@fortawesome/free-solid-svg-icons@^6.4.0": + version "6.4.0" + resolved "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.4.0.tgz" + integrity sha512-kutPeRGWm8V5dltFP1zGjQOEAzaLZj4StdQhWVZnfGFCvAPVvHh8qk5bRrU4KXnRRRNni5tKQI9PBAdI6MP8nQ== + dependencies: + "@fortawesome/fontawesome-common-types" "6.4.0" + +"@fortawesome/react-fontawesome@^0.2.0": + version "0.2.0" + resolved "https://registry.npmjs.org/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.0.tgz" + integrity sha512-uHg75Rb/XORTtVt7OS9WoK8uM276Ufi7gCzshVWkUJbHhh3svsUUeqXerrM96Wm7fRiDzfKRwSoahhMIkGAYHw== + dependencies: + prop-types "^15.8.1" + "@humanwhocodes/config-array@^0.11.10": version "0.11.10" resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.10.tgz" @@ -7909,7 +7942,7 @@ react-scripts@5.0.1: optionalDependencies: fsevents "^2.3.2" -react@*, react@^18.0.0, react@^18.2.0, "react@>= 16", react@>=16, react@>=16.8, react@>=16.8.0: +react@*, react@^18.0.0, react@^18.2.0, "react@>= 16", react@>=16, react@>=16.3, react@>=16.8, react@>=16.8.0: version "18.2.0" resolved "https://registry.npmjs.org/react/-/react-18.2.0.tgz" integrity sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==