diff options
| author | realtradam <[email protected]> | 2024-07-27 04:17:50 -0400 |
|---|---|---|
| committer | realtradam <[email protected]> | 2024-07-27 04:17:50 -0400 |
| commit | cc04a47f4e1597b4fe3d92235929d553205dac4a (patch) | |
| tree | 6732b2ce0e604910a656d5ac441272b80506b1d4 /frontend/src/pages | |
| parent | de3d80ce3ea20a869d700c3238020d44059de099 (diff) | |
| download | spring-blog-cc04a47f4e1597b4fe3d92235929d553205dac4a.tar.gz spring-blog-cc04a47f4e1597b4fe3d92235929d553205dac4a.zip | |
implement search and better UX
Diffstat (limited to 'frontend/src/pages')
| -rw-r--r-- | frontend/src/pages/Home.tsx | 297 | ||||
| -rw-r--r-- | frontend/src/pages/auth/Login.tsx | 137 |
2 files changed, 259 insertions, 175 deletions
diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index eed745b..682f794 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -1,123 +1,194 @@ import { useState, useEffect } from "react"; -export default function Home() { - const [articles, setArticles] = useState<any>([]); - +type article = { + id: number; + title: string; + photoUrl: string; + content: string; + createdOn: string; + updateOn: string; +}; +type articleSearch = { + set: React.Dispatch<React.SetStateAction<string | null>>; + value: string | null; +}; + +export default function Home({ + articleSearch, +}: { + articleSearch: articleSearch; +}) { + const [articles, setArticles] = useState<article[]>([]); + const [allArticles, setAllArticles] = useState<any>(null); + + // pull data when new search is given useEffect(() => { - const url = `${import.meta.env.VITE_API_TITLE}/api/v1/articles`; - fetch(url).then((response) => { - if (response.ok) { - return response.json(); - } - throw new Error("Network response was not ok."); - }).then((response) => setArticles(response)); - }, []); - - const allArticles = articles.map((article) => ( - <div className="w-full md:w-1/2 p-6 flex flex-col flex-grow flex-shrink"> - <div className="flex-1 bg-white rounded-t rounded-b-none overflow-hidden shadow-lg"> - {/*th:href="@{/articles/{articleId}(articleId=${article.id})}"*/} - <a className="flex flex-wrap no-underline hover:no-underline"> - {/*th:src="${article.photoUrl}"*/} - <img src={article.photoUrl} className="h-full w-full rounded-t pb-6"/> - {/*th:text="${article.title}"*/} - <div className="w-full font-bold text-xl text-gray-900 px-6">{article.title}</div> - <p className="text-gray-800 font-serif text-base px-6 mb-5"></p> - </a> + let url; + if (articleSearch.value === null) { + //alert("not searched"); + url = `${import.meta.env.VITE_API_TITLE}/api/v1/articles`; + } else { + //alert("searched"); + url = `${import.meta.env.VITE_API_TITLE}/api/v1/articles?search=${ + articleSearch.value + }`; + } + fetch(url) + .then((response) => { + if (response.ok) { + return response.json(); + } + throw new Error("Network response was not ok."); + }) + .then((response) => setArticles(response)); + }, [articleSearch.value]); + + // when new data is pulled update the articles shown + useEffect(() => { + setAllArticles( + articles.map((article) => ( + <div + key={article.id} + className="w-full md:w-1/2 p-6 flex flex-col flex-grow flex-shrink"> + <div className="flex-1 bg-white rounded-t rounded-b-none overflow-hidden shadow-lg"> + {/*th:href="@{/articles/{articleId}(articleId=${article.id})}"*/} + <a className="flex flex-wrap no-underline hover:no-underline"> + <img src={article.photoUrl} className="h-full w-full rounded-t pb-6" /> + <div className="w-full font-bold text-xl text-gray-900 px-6"> + {article.title} + </div> + <p className="text-gray-800 font-serif text-base px-6 mb-5"></p> + </a> {/*th:if="${user.id} == ${article.createdBy.id}"*/} - <div ></div> + <div></div> {/*th:href="@{/articles/edit/{articleId}(articleId=${article.id})}"*/} - <a className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 ml-4 text-sm rounded">Edit</a> - {/*th:href="@{/articles/delete/{articleId}(articleId=${article.id})}"*/} - <a className="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-2 ml-4 text-sm rounded">Delete</a> - - </div> - <div className="flex-none mt-auto bg-white rounded-b rounded-t-none overflow-hidden shadow-lg p-6"> - <div className="flex items-center justify-between"> - <p className="text-gray-600 text-xs md:text-sm"></p> - </div> - </div> - </div> - )); - return( + <a className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-1 px-2 ml-4 text-sm rounded"> + Edit + </a> + {/*th:href="@{/articles/delete/{articleId}(articleId=${article.id})}"*/} + <a className="bg-red-500 hover:bg-red-700 text-white font-bold py-1 px-2 ml-4 text-sm rounded"> + Delete + </a> + </div> + <div className="flex-none mt-auto bg-white rounded-b rounded-t-none overflow-hidden shadow-lg p-6"> + <div className="flex items-center justify-between"> + <p className="text-gray-600 text-xs md:text-sm"></p> + </div> + </div> + </div> + )), + ); + }, [articles]); + + return ( <> - {/*Container*/} -<div className="container px-4 md:px-0 max-w-6xl mx-auto -mt-32"> - - <div className="mx-0 sm:mx-6"> - - {/*<!--Nav-->*/} - <nav className="mt-0 w-full"> - <div className="container mx-auto flex items-center"> - - <div className="flex w-1/2 pl-4 text-sm"> - <ul className="list-reset flex justify-between flex-1 md:flex-none items-center"> - <li className="mr-2"> - <a className="inline-block py-2 px-2 text-white no-underline hover:underline" href="post.html">POST</a> - </li> - <li className="mr-2"> - <a className="inline-block text-gray-600 no-underline hover:text-gray-200 hover:underline py-2 px-2" href="multimenu post.html">MULTIMENU POST</a> - </li> - <li className="mr-2"> - <a className="inline-block text-gray-600 no-underline hover:text-gray-200 hover:underline py-2 px-2" href="#">LINK</a> - </li> - <li className="mr-2"> - <a className="inline-block text-gray-600 no-underline hover:text-gray-200 hover:underline py-2 px-2" href="post_vue.html">POST_VUE</a> - </li> - </ul> - </div> - - - <div className="flex w-1/2 justify-end content-center"> - <a className="inline-block text-gray-500 no-underline hover:text-white hover:text-underline text-center h-10 p-2 md:h-auto md:p-4 avatar" data-tippy-content="@twitter_handle" href="https://twitter.com/intent/tweet?url=#"> - <svg className="fill-current h-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z"></path></svg> - </a> - <a className="inline-block text-gray-500 no-underline hover:text-white hover:text-underline text-center h-10 p-2 md:h-auto md:p-4 avatar" data-tippy-content="#facebook_id" href="https://www.facebook.com/sharer/sharer.php?u=#"> - <svg className="fill-current h-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><path d="M19 6h5V0h-5c-3.86 0-7 3.14-7 7v3H8v6h4v16h6V16h5l1-6h-6V7c0-.542.458-1 1-1z"></path></svg> - </a> - </div> - - </div> - </nav> - - <div className="bg-gray-200 w-full text-xl md:text-2xl text-gray-800 leading-normal rounded-t"> - - {/*<!--Lead Card-->*/} - <div className="flex h-full bg-contain rounded overflow-hidden shadow-lg" style={{backgroundImage: "url('/public/abstract-polygonal-banner-background-vector.jpg')"}}> - <a href="post.html" className="flex flex-wrap no-underline hover:no-underline"> - <div className="w-full md:w-2/3 rounded-t"> - </div> - - <div className="w-full md:w-1/3 flex flex-col flex-grow flex-shrink"> - <div className="flex-1 bg-white rounded-t rounded-b-none overflow-hidden shadow-lg"> - <p className="w-full text-gray-600 text-xs md:text-sm pt-6 px-6">Spring Blog</p> - <div className="w-full font-bold text-xl text-gray-900 px-6">👋 Welcome to my Java Spring Blog!</div> - <p className="text-gray-800 font-serif text-base px-6 mb-5"> - This is a blog project I have created with the goal of learning and understand the ins and outs of the Java Spring framework. - </p> - </div> - - <div className="flex-none mt-auto bg-white rounded-b rounded-t-none overflow-hidden shadow-lg p-6"> - <div className="flex items-center justify-between"> - <p className="text-gray-600 text-xs md:text-sm"></p> - </div> - </div> - </div> - - </a> - </div> - {/*<!--/Lead Card-->*/} -{/*th:if="${param.success}"*/} - <div className="text-xl p-4 bg-black text-red-500">Successful Registration!</div> - - - {/*<!--Posts Container-->*/} - <div className="flex flex-wrap justify-between pt-12 -mx-6"> - { allArticles } + {/*Container*/} + <div className="container px-4 md:px-0 max-w-6xl mx-auto -mt-32"> + <div className="mx-0 sm:mx-6"> + {/*<!--Nav-->*/} + <nav className="mt-0 w-full"> + <div className="container mx-auto flex items-center"> + <div className="flex w-1/2 pl-4 text-sm"> + <ul className="list-reset flex justify-between flex-1 md:flex-none items-center"> + <li className="mr-2"> + <a + className="inline-block py-2 px-2 text-white no-underline hover:underline" + href="post.html"> + POST + </a> + </li> + <li className="mr-2"> + <a + className="inline-block text-gray-600 no-underline hover:text-gray-200 hover:underline py-2 px-2" + href="multimenu post.html"> + MULTIMENU POST + </a> + </li> + <li className="mr-2"> + <a + className="inline-block text-gray-600 no-underline hover:text-gray-200 hover:underline py-2 px-2" + href="#"> + LINK + </a> + </li> + <li className="mr-2"> + <a + className="inline-block text-gray-600 no-underline hover:text-gray-200 hover:underline py-2 px-2" + href="post_vue.html"> + POST_VUE + </a> + </li> + </ul> + </div> + + <div className="flex w-1/2 justify-end content-center"> + <a + className="inline-block text-gray-500 no-underline hover:text-white hover:text-underline text-center h-10 p-2 md:h-auto md:p-4 avatar" + data-tippy-content="@twitter_handle" + href="https://twitter.com/intent/tweet?url=#"> + <svg + className="fill-current h-4" + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 32 32"> + <path d="M30.063 7.313c-.813 1.125-1.75 2.125-2.875 2.938v.75c0 1.563-.188 3.125-.688 4.625a15.088 15.088 0 0 1-2.063 4.438c-.875 1.438-2 2.688-3.25 3.813a15.015 15.015 0 0 1-4.625 2.563c-1.813.688-3.75 1-5.75 1-3.25 0-6.188-.875-8.875-2.625.438.063.875.125 1.375.125 2.688 0 5.063-.875 7.188-2.5-1.25 0-2.375-.375-3.375-1.125s-1.688-1.688-2.063-2.875c.438.063.813.125 1.125.125.5 0 1-.063 1.5-.25-1.313-.25-2.438-.938-3.313-1.938a5.673 5.673 0 0 1-1.313-3.688v-.063c.813.438 1.688.688 2.625.688a5.228 5.228 0 0 1-1.875-2c-.5-.875-.688-1.813-.688-2.75 0-1.063.25-2.063.75-2.938 1.438 1.75 3.188 3.188 5.25 4.25s4.313 1.688 6.688 1.813a5.579 5.579 0 0 1 1.5-5.438c1.125-1.125 2.5-1.688 4.125-1.688s3.063.625 4.188 1.813a11.48 11.48 0 0 0 3.688-1.375c-.438 1.375-1.313 2.438-2.563 3.188 1.125-.125 2.188-.438 3.313-.875z"></path> + </svg> + </a> + <a + className="inline-block text-gray-500 no-underline hover:text-white hover:text-underline text-center h-10 p-2 md:h-auto md:p-4 avatar" + data-tippy-content="#facebook_id" + href="https://www.facebook.com/sharer/sharer.php?u=#"> + <svg + className="fill-current h-4" + xmlns="http://www.w3.org/2000/svg" + viewBox="0 0 32 32"> + <path d="M19 6h5V0h-5c-3.86 0-7 3.14-7 7v3H8v6h4v16h6V16h5l1-6h-6V7c0-.542.458-1 1-1z"></path> + </svg> + </a> + </div> + </div> + </nav> + + <div className="bg-gray-200 w-full text-xl md:text-2xl text-gray-800 leading-normal rounded-t"> + {/*<!--Lead Card-->*/} + <div + className="flex h-full bg-contain rounded overflow-hidden shadow-lg" + style={{ + backgroundImage: + "url('/public/abstract-polygonal-banner-background-vector.jpg')", + }}> + <a + href="post.html" + className="flex flex-wrap no-underline hover:no-underline"> + <div className="w-full md:w-2/3 rounded-t"></div> + + <div className="w-full md:w-1/3 flex flex-col flex-grow flex-shrink"> + <div className="flex-1 bg-white rounded-t rounded-b-none overflow-hidden shadow-lg"> + <p className="w-full text-gray-600 text-xs md:text-sm pt-6 px-6"> + Spring Blog + </p> + <div className="w-full font-bold text-xl text-gray-900 px-6"> + 👋 Welcome to my Java Spring Blog! + </div> + <p className="text-gray-800 font-serif text-base px-6 mb-5"> + This is a blog project I have created with the goal of learning and + understand the ins and outs of the Java Spring framework. + </p> + </div> + + <div className="flex-none mt-auto bg-white rounded-b rounded-t-none overflow-hidden shadow-lg p-6"> + <div className="flex items-center justify-between"> + <p className="text-gray-600 text-xs md:text-sm"></p> + </div> + </div> + </div> + </a> + </div> + <div className="flex flex-wrap justify-between pt-12 -mx-6"> + {allArticles} + </div> + </div> + </div> </div> - </div> - </div> -</div> </> ); } diff --git a/frontend/src/pages/auth/Login.tsx b/frontend/src/pages/auth/Login.tsx index 5a1e858..d064acf 100644 --- a/frontend/src/pages/auth/Login.tsx +++ b/frontend/src/pages/auth/Login.tsx @@ -2,12 +2,15 @@ import { FormEvent } from "react"; import { useNavigate } from "react-router-dom"; //type setUser = { setUser: { func: React.Dispatch<React.SetStateAction<string | null>> } }; -type user = { set: React.Dispatch<React.SetStateAction<string | null>>, value: string | null }; +type user = { + set: React.Dispatch<React.SetStateAction<string | null>>; + value: string | null; +}; -export default function Login ({user}: {user: user}) { +export default function Login({ user }: { user: user }) { const navigate = useNavigate(); -const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { + const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { e.preventDefault(); //stops submit from happening const target = e.target as typeof e.target & { @@ -17,75 +20,85 @@ const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { }; const formData = new FormData(); - formData.append('username', target.username.value); - formData.append('password', target.password.value); + formData.append("username", target.username.value); + formData.append("password", target.password.value); - const response = await fetch(`${import.meta.env.VITE_API_TITLE}/api/v1/login`, { - credentials: 'include', - method: 'post', - body: formData, - }).then((res) => { - if(res.ok) { + const response = await fetch( + `${import.meta.env.VITE_API_TITLE}/api/v1/login`, + { + credentials: "include", + method: "post", + body: formData, + }, + ).then((res) => { + if (res.ok) { const url = `${import.meta.env.VITE_API_TITLE}/api/v1/profile`; fetch(url, { - credentials: 'include', - method: 'get', - }).then((response) => { - if (response.ok) { - return response.json(); - } - throw new Error("Network response was not ok."); - }).then((response) => { - user.set(response.username); - console.log("USER:"); - console.log(user); - console.log(user.value); - console.log(response.username); - navigate("/"); - }); - } - else { + credentials: "include", + method: "get", + }) + .then((response) => { + if (response.ok) { + return response.json(); + } + throw new Error("Network response was not ok."); + }) + .then((response) => { + user.set(response.username); + console.log("USER:"); + console.log(user); + console.log(user.value); + console.log(response.username); + navigate("/"); + }); + } else { console.log(response); alert("check console for error"); } }); }; - return( + return ( <> -<div className="flex h-full justify-center bg-white p-12"> - <form onSubmit={handleSubmit} method="post" className="w-full max-w-lg"> - <div className="flex flex-wrap -mx-3 mb-6"> - <div className="w-full md:w-1/2 px-3 mb-6 md:mb-0"> - <label className="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"> - Title - </label> - <input className="appearance-none block w-full bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" - id="username" - type="text" - name="username" - placeholder="Ted"/> - </div> - </div> - <div className="flex flex-wrap -mx-3 mb-6"> - <div className="w-full px-3"> - <label className="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"> - Password - </label> - <input className="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" - id="password" - type="password" - name="password" - placeholder="Doe"/> - </div> - </div> - <div className="flex flex-wrap mb-2"> - </div> - <button type="submit" value="Log in" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Log In</button> - - </form> -</div> + <div className="flex h-full justify-center bg-white p-12"> + <form onSubmit={handleSubmit} method="post" className="w-full max-w-lg"> + <div className="flex flex-wrap -mx-3 mb-6"> + <div className="w-full md:w-1/2 px-3 mb-6 md:mb-0"> + <label className="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"> + Title + </label> + <input + className="appearance-none block w-full bg-gray-200 text-gray-700 border rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" + id="username" + type="text" + name="username" + placeholder="Ted" + /> + </div> + </div> + <div className="flex flex-wrap -mx-3 mb-6"> + <div className="w-full px-3"> + <label className="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"> + Password + </label> + <input + className="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" + id="password" + type="password" + name="password" + placeholder="Doe" + /> + </div> + </div> + <div className="flex flex-wrap mb-2"></div> + <button + type="submit" + value="Log in" + className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded"> + Log In + </button> + </form> + </div> </> ); - } |
