diff options
| author | realtradam <[email protected]> | 2024-07-27 16:44:01 -0400 |
|---|---|---|
| committer | realtradam <[email protected]> | 2024-07-27 16:44:01 -0400 |
| commit | f75c5d9264d71298711321d83a9c6b23327b3f56 (patch) | |
| tree | b7f964a1e37cdead6a198e1138cc1f06331b0eb5 /frontend | |
| parent | b1112afc5162bb299d528974594dcf7c2ec46266 (diff) | |
| download | spring-blog-f75c5d9264d71298711321d83a9c6b23327b3f56.tar.gz spring-blog-f75c5d9264d71298711321d83a9c6b23327b3f56.zip | |
fix linting
Diffstat (limited to 'frontend')
| -rw-r--r-- | frontend/.eslintrc.cjs | 18 | ||||
| -rw-r--r-- | frontend/.vite/deps/_metadata.json | 2 | ||||
| -rw-r--r-- | frontend/README.md | 8 | ||||
| -rw-r--r-- | frontend/index.html | 2 | ||||
| -rw-r--r-- | frontend/postcss.config.js | 2 | ||||
| -rw-r--r-- | frontend/src/App.tsx | 4 | ||||
| -rw-r--r-- | frontend/src/components/Layout.tsx | 471 | ||||
| -rw-r--r-- | frontend/src/main.tsx | 12 | ||||
| -rw-r--r-- | frontend/src/pages/Home.tsx | 368 | ||||
| -rw-r--r-- | frontend/src/pages/articles/Article.tsx | 46 | ||||
| -rw-r--r-- | frontend/src/pages/articles/New.tsx | 161 | ||||
| -rw-r--r-- | frontend/src/pages/auth/Login.tsx | 181 | ||||
| -rw-r--r-- | frontend/src/pages/auth/Register.tsx | 161 | ||||
| -rw-r--r-- | frontend/src/routes/index.tsx | 55 | ||||
| -rw-r--r-- | frontend/tailwind.config.js | 8 | ||||
| -rw-r--r-- | frontend/vite.config.ts | 6 |
16 files changed, 794 insertions, 711 deletions
diff --git a/frontend/.eslintrc.cjs b/frontend/.eslintrc.cjs index d6c9537..6e8698b 100644 --- a/frontend/.eslintrc.cjs +++ b/frontend/.eslintrc.cjs @@ -2,17 +2,17 @@ module.exports = { root: true, env: { browser: true, es2020: true }, extends: [ - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended', - 'plugin:react-hooks/recommended', + "eslint:recommended", + "plugin:@typescript-eslint/recommended", + "plugin:react-hooks/recommended", ], - ignorePatterns: ['dist', '.eslintrc.cjs'], - parser: '@typescript-eslint/parser', - plugins: ['react-refresh'], + ignorePatterns: ["dist", ".eslintrc.cjs"], + parser: "@typescript-eslint/parser", + plugins: ["react-refresh"], rules: { - 'react-refresh/only-export-components': [ - 'warn', + "react-refresh/only-export-components": [ + "warn", { allowConstantExport: true }, ], }, -} +}; diff --git a/frontend/.vite/deps/_metadata.json b/frontend/.vite/deps/_metadata.json index 905310f..9304faf 100644 --- a/frontend/.vite/deps/_metadata.json +++ b/frontend/.vite/deps/_metadata.json @@ -5,4 +5,4 @@ "browserHash": "f33efd09", "optimized": {}, "chunks": {} -}
\ No newline at end of file +} diff --git a/frontend/README.md b/frontend/README.md index e1cdc89..85a6989 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -17,12 +17,12 @@ If you are developing a production application, we recommend updating the config export default { // other rules... parserOptions: { - ecmaVersion: 'latest', - sourceType: 'module', - project: ['./tsconfig.json', './tsconfig.node.json', './tsconfig.app.json'], + ecmaVersion: "latest", + sourceType: "module", + project: ["./tsconfig.json", "./tsconfig.node.json", "./tsconfig.app.json"], tsconfigRootDir: __dirname, }, -} +}; ``` - Replace `plugin:@typescript-eslint/recommended` to `plugin:@typescript-eslint/recommended-type-checked` or `plugin:@typescript-eslint/strict-type-checked` diff --git a/frontend/index.html b/frontend/index.html index 82a3d13..821eeac 100644 --- a/frontend/index.html +++ b/frontend/index.html @@ -10,4 +10,4 @@ <div id="root" class="w-full"></div> <script type="module" src="/src/main.tsx"></script> </body> -</div> +</html> diff --git a/frontend/postcss.config.js b/frontend/postcss.config.js index 2e7af2b..2aa7205 100644 --- a/frontend/postcss.config.js +++ b/frontend/postcss.config.js @@ -3,4 +3,4 @@ export default { tailwindcss: {}, autoprefixer: {}, }, -} +}; diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 92de410..e66807e 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -1,5 +1,5 @@ -import Routes from "./routes" +import Routes from "./routes"; export default function App() { - return (<Routes />); + return <Routes />; } diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index 2ebaa79..d8613d5 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -1,246 +1,269 @@ import { Outlet, useNavigate } from "react-router-dom"; -import { useState, useEffect, FormEvent } from "react"; +import { useEffect, FormEvent } from "react"; type user = { - set: React.Dispatch<React.SetStateAction<string | null>>; - value: string | null; + set: React.Dispatch<React.SetStateAction<string | null>>; + value: string | null; }; type articleSearch = user; export default function Layout({ - user, - articleSearch, + user, + articleSearch, }: { - user: user; - articleSearch: articleSearch; + user: user; + articleSearch: articleSearch; }) { - const navigate = useNavigate(); + const navigate = useNavigate(); - useEffect(() => { - 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(response.username); - }); - }, [user]); + useEffect(() => { + 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(response.username); + }); + }, [user]); - const logout = () => { - fetch(`${import.meta.env.VITE_API_TITLE}/api/v1/logout`, { - credentials: "include", - method: "get", - }).then(() => { - user.set(null); - }); - }; + const logout = () => { + fetch(`${import.meta.env.VITE_API_TITLE}/api/v1/logout`, { + credentials: "include", + method: "get", + }).then(() => { + user.set(null); + }); + }; - const search = (e: FormEvent<HTMLFormElement>) => { - e.preventDefault(); + const search = (e: FormEvent<HTMLFormElement>) => { + e.preventDefault(); - const target = e.target as typeof e.target & { - search: { value: string }; - }; + const target = e.target as typeof e.target & { + search: { value: string }; + }; - articleSearch.set(target.search.value); + articleSearch.set(target.search.value); - navigate("/"); - }; + navigate("/"); + }; - return ( - <> - <div className="w-full bg-gray-200 min-h-screen font-sans leading-normal tracking-normal"> - <nav className="bg-gray-900 p-4 mt-0 w-full"> - <div className="container mx-auto flex items-center"> - <div className="flex text-white font-extrabold"> - {/*th:if="${(user == null || user.username == null)}"*/} - <a - className="flex text-white text-base no-underline whitespace-nowrap hover:text-white hover:no-underline" - href="#"> - ☕ {user.value === null ? "Spring!" : user.value} - <span className="hidden w-0 md:w-auto md:block pl-1"></span> - </a> - </div> - <div className="flex pl-4 text-sm place-content-between w-full"> - <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" href="/"> - HOME - </a> - </li> - <li className="mr-2"> - <a - className="inline-block text-indigo-200 no-underline hover:text-gray-100 hover:text-underline py-2 px-2" - href="/article/new"> - NEW - </a> - </li> - <li className="mr-2"> - <a - className="inline-block text-indigo-200 no-underline hover:text-indigo-100 hover:text-underline py-2 px-2" - href="/register"> - REGISTER - </a> - </li> - <li className="mr-2"> - {user.value === null ? ( - <a - className="inline-block text-indigo-200 no-underline hover:text-indigo-100 hover:text-underline py-2 px-2" - href="/login"> - LOGIN - </a> - ) : ( - <button - className="inline-block text-indigo-200 no-underline hover:text-indigo-100 hover:text-underline py-2 px-2" - onClick={logout}> - LOGOUT - </button> - )} - </li> - </ul> - <form onSubmit={search} className="w-full max-w-md"> - <div className="flex flex-wrap -mx-3"> - <div className="w-full px-3"> - <input - className="appearance-none block w-full bg-gray-200 text-gray-700 border rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white" - id="search" - type="search" - name="search" - placeholder="Search" - /> - </div> - </div> - </form> - </div> - </div> - </nav> + return ( + <> + <div className="w-full bg-gray-200 min-h-screen font-sans leading-normal tracking-normal"> + <nav className="bg-gray-900 p-4 mt-0 w-full"> + <div className="container mx-auto flex items-center"> + <div className="flex text-white font-extrabold"> + {/*th:if="${(user == null || user.username == null)}"*/} + <a + className="flex text-white text-base no-underline whitespace-nowrap hover:text-white hover:no-underline" + href="#" + > + ☕ {user.value === null ? "Spring!" : user.value} + <span className="hidden w-0 md:w-auto md:block pl-1"></span> + </a> + </div> + <div className="flex pl-4 text-sm place-content-between w-full"> + <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" + href="/" + > + HOME + </a> + </li> + <li className="mr-2"> + <a + className="inline-block text-indigo-200 no-underline hover:text-gray-100 hover:text-underline py-2 px-2" + href="/article/new" + > + NEW + </a> + </li> + <li className="mr-2"> + <a + className="inline-block text-indigo-200 no-underline hover:text-indigo-100 hover:text-underline py-2 px-2" + href="/register" + > + REGISTER + </a> + </li> + <li className="mr-2"> + {user.value === null ? ( + <a + className="inline-block text-indigo-200 no-underline hover:text-indigo-100 hover:text-underline py-2 px-2" + href="/login" + > + LOGIN + </a> + ) : ( + <button + className="inline-block text-indigo-200 no-underline hover:text-indigo-100 hover:text-underline py-2 px-2" + onClick={logout} + > + LOGOUT + </button> + )} + </li> + </ul> + <form onSubmit={search} className="w-full max-w-md"> + <div className="flex flex-wrap -mx-3"> + <div className="w-full px-3"> + <input + className="appearance-none block w-full bg-gray-200 text-gray-700 border rounded py-3 px-4 leading-tight focus:outline-none focus:bg-white" + id="search" + type="search" + name="search" + placeholder="Search" + /> + </div> + </div> + </form> + </div> + </div> + </nav> - {/*slide in nav*/} - <div - id="header" - className="bg-white fixed w-full z-10 top-0 hidden animated" - style={{ opacity: ".95" }}> - <div className="bg-white"> - <div className="flex flex-wrap items-center content-center"> - <div className="flex w-1/2 justify-start text-white font-extrabold"> - <a - className="flex text-gray-100 no-underline hover:text-gray-900 hover:no-underline pl-2" - href="#"> - 👻{" "} - <span className="hidden w-0 md:w-auto md:block pl-1"> - Ghostwind CSS - </span> - </a> - </div> - <div className="flex w-1/2 justify-end content-center"> - <p className="hidden sm:block mr-3 text-center h-14 p-4 text-xs"> - <span className="pr-2">Share this</span> 👉 - </p> - <a - className="inline-block text-white no-underline hover:text-white hover:text-underline text-center h-10 w-10 p-2 md:h-auto md:w-16 md:p-4" - href="https://twitter.com/intent/tweet?url=#" - style={{ backgroundColor: "#33b1ff" }}> - <svg - className="fill-current text-white 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-white no-underline hover:text-white hover:text-underline text-center h-10 w-10 p-2 md:h-auto md:w-16 md:p-4" - href="https://www.facebook.com/sharer/sharer.php?u=#" - style={{ backgroundColor: "#005e99" }}> - <svg - className="fill-current text-white 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> - </div> - {/*Progress bar*/} - <div - id="progress" - className="h-1 bg-white shadow" - style={{ - background: - "linear-gradient(to right, #4dc0b5 var(--scroll), transparent 0)", - }}></div> - </div> + {/*slide in nav*/} + <div + id="header" + className="bg-white fixed w-full z-10 top-0 hidden animated" + style={{ opacity: ".95" }} + > + <div className="bg-white"> + <div className="flex flex-wrap items-center content-center"> + <div className="flex w-1/2 justify-start text-white font-extrabold"> + <a + className="flex text-gray-100 no-underline hover:text-gray-900 hover:no-underline pl-2" + href="#" + > + 👻{" "} + <span className="hidden w-0 md:w-auto md:block pl-1"> + Ghostwind CSS + </span> + </a> + </div> + <div className="flex w-1/2 justify-end content-center"> + <p className="hidden sm:block mr-3 text-center h-14 p-4 text-xs"> + <span className="pr-2">Share this</span> 👉 + </p> + <a + className="inline-block text-white no-underline hover:text-white hover:text-underline text-center h-10 w-10 p-2 md:h-auto md:w-16 md:p-4" + href="https://twitter.com/intent/tweet?url=#" + style={{ backgroundColor: "#33b1ff" }} + > + <svg + className="fill-current text-white 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-white no-underline hover:text-white hover:text-underline text-center h-10 w-10 p-2 md:h-auto md:w-16 md:p-4" + href="https://www.facebook.com/sharer/sharer.php?u=#" + style={{ backgroundColor: "#005e99" }} + > + <svg + className="fill-current text-white 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> + </div> + {/*Progress bar*/} + <div + id="progress" + className="h-1 bg-white shadow" + style={{ + background: + "linear-gradient(to right, #4dc0b5 var(--scroll), transparent 0)", + }} + ></div> + </div> - {/*Header*/} - <div - className="w-full m-0 p-0 bg-cover bg-bottom" - style={{ - backgroundImage: - "url('https://upload.wikimedia.org/wikipedia/commons/6/65/Toronto_Skyline_Summer_2020.jpg')", - height: "60vh", - maxHeight: "460px", - }}> - <div className="container max-w-4xl bg-black bg-opacity-50 pb-16 rounded-b-xl mx-auto pt-16 md:pt-32 text-center break-normal"> - {/*Title*/} - <p className="text-white font-extrabold text-3xl md:text-5xl"> - ☕ Spring! - </p> - <p className="text-xl md:text-2xl text-gray-200">Welcome to my Blog</p> - </div> - </div> + {/*Header*/} + <div + className="w-full m-0 p-0 bg-cover bg-bottom" + style={{ + backgroundImage: + "url('https://upload.wikimedia.org/wikipedia/commons/6/65/Toronto_Skyline_Summer_2020.jpg')", + height: "60vh", + maxHeight: "460px", + }} + > + <div className="container max-w-4xl bg-black bg-opacity-50 pb-16 rounded-b-xl mx-auto pt-16 md:pt-32 text-center break-normal"> + {/*Title*/} + <p className="text-white font-extrabold text-3xl md:text-5xl"> + ☕ Spring! + </p> + <p className="text-xl md:text-2xl text-gray-200"> + Welcome to my Blog + </p> + </div> + </div> - <Outlet /> + <Outlet /> - <footer className="bg-gray-900"> - <div className="container max-w-6xl mx-auto flex items-center px-2 py-8"> - <div className="w-full mx-auto flex flex-wrap items-center"> - <div className="flex w-full md:w-1/2 justify-center md:justify-start text-white font-extrabold"> - <a - className="text-gray-900 no-underline hover:text-gray-900 hover:no-underline" - href="#"> - <span className="text-base text-gray-200"></span> - </a> - </div> - <div className="flex w-full pt-2 content-center justify-between md:w-1/2 md:justify-end"> - <ul className="list-reset flex justify-center flex-1 md:flex-none items-center"> - <li> - <a - className="inline-block py-2 px-3 text-white no-underline" - href="#"></a> - </li> - <li> - <a - className="inline-block text-gray-600 no-underline hover:text-gray-200 hover:underline py-2 px-3" - href="#"></a> - </li> - <li> - <a - className="inline-block text-gray-600 no-underline hover:text-gray-200 hover:underline py-2 px-3" - href="#"></a> - </li> - <li> - <a - className="inline-block text-gray-600 no-underline hover:text-gray-200 hover:underline py-2 px-3" - href="#"></a> - </li> - </ul> - </div> - </div> - </div> - </footer> + <footer className="bg-gray-900"> + <div className="container max-w-6xl mx-auto flex items-center px-2 py-8"> + <div className="w-full mx-auto flex flex-wrap items-center"> + <div className="flex w-full md:w-1/2 justify-center md:justify-start text-white font-extrabold"> + <a + className="text-gray-900 no-underline hover:text-gray-900 hover:no-underline" + href="#" + > + <span className="text-base text-gray-200"></span> + </a> + </div> + <div className="flex w-full pt-2 content-center justify-between md:w-1/2 md:justify-end"> + <ul className="list-reset flex justify-center flex-1 md:flex-none items-center"> + <li> + <a + className="inline-block py-2 px-3 text-white no-underline" + href="#" + ></a> + </li> + <li> + <a + className="inline-block text-gray-600 no-underline hover:text-gray-200 hover:underline py-2 px-3" + href="#" + ></a> + </li> + <li> + <a + className="inline-block text-gray-600 no-underline hover:text-gray-200 hover:underline py-2 px-3" + href="#" + ></a> + </li> + <li> + <a + className="inline-block text-gray-600 no-underline hover:text-gray-200 hover:underline py-2 px-3" + href="#" + ></a> + </li> + </ul> + </div> + </div> + </div> + </footer> - <script src="https://unpkg.com/@popperjs/core@2"></script> - <script src="https://unpkg.com/tippy.js@6"></script> - <script>//Init tooltips tippy('.avatar')</script> - </div> - </> - ); + <script src="https://unpkg.com/@popperjs/core@2"></script> + <script src="https://unpkg.com/tippy.js@6"></script> + <script>//Init tooltips tippy('.avatar')</script> + </div> + </> + ); } diff --git a/frontend/src/main.tsx b/frontend/src/main.tsx index 3d7150d..f25366e 100644 --- a/frontend/src/main.tsx +++ b/frontend/src/main.tsx @@ -1,10 +1,10 @@ -import React from 'react' -import ReactDOM from 'react-dom/client' -import App from './App.tsx' -import './index.css' +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App.tsx"; +import "./index.css"; -ReactDOM.createRoot(document.getElementById('root')!).render( +ReactDOM.createRoot(document.getElementById("root")!).render( <React.StrictMode> <App /> </React.StrictMode>, -) +); diff --git a/frontend/src/pages/Home.tsx b/frontend/src/pages/Home.tsx index 682f794..e0866a4 100644 --- a/frontend/src/pages/Home.tsx +++ b/frontend/src/pages/Home.tsx @@ -1,194 +1,210 @@ import { useState, useEffect } from "react"; type article = { - id: number; - title: string; - photoUrl: string; - content: string; - createdOn: string; - updateOn: string; + id: number; + title: string; + photoUrl: string; + content: string; + createdOn: string; + updateOn: string; }; +// if null then code will know to not search and just return all articles type articleSearch = { - set: React.Dispatch<React.SetStateAction<string | null>>; - value: string | null; + set: React.Dispatch<React.SetStateAction<string | null>>; + value: string | null; }; export default function Home({ - articleSearch, + articleSearch, }: { - articleSearch: articleSearch; + articleSearch: articleSearch; }) { - const [articles, setArticles] = useState<article[]>([]); - const [allArticles, setAllArticles] = useState<any>(null); + const [articles, setArticles] = useState<article[]>([]); + const [allArticles, setAllArticles] = useState<JSX.Element[]>([]); - // pull data when new search is given - useEffect(() => { - 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]); + // pull data when new search is given + useEffect(() => { + 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> - {/*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> - )), - ); - }, [articles]); + // 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> + {/*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> + )), + ); + }, [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> + 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="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="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="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 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> + </> + ); } diff --git a/frontend/src/pages/articles/Article.tsx b/frontend/src/pages/articles/Article.tsx index b367811..1a96ada 100644 --- a/frontend/src/pages/articles/Article.tsx +++ b/frontend/src/pages/articles/Article.tsx @@ -1,25 +1,35 @@ import { useState, useEffect } from "react"; import { useParams } from "react-router-dom"; -export default function Article () { - const { id } = useParams(); - const [articleData, setArticleData] = useState<any>(); +type article = { + id: number; + title: string; + photoUrl: string; + content: string; + createdOn: string; + updateOn: string; +}; - useEffect(() => { - const url = `${import.meta.env.VITE_API_TITLE}/api/v1/article/${id}`; - fetch(url).then((response) => { - if (response.ok) { - return response.json(); - } - throw new Error("Network response was not ok."); - }).then((response) => setArticleData(response)); //.catch(() => navigate("/")); - }, [id]); +export default function Article() { + const { id } = useParams(); + const [articleData, setArticleData] = useState<article>(); - return( - <> - <h1>{articleData?.title}</h1> - <div>{articleData?.content}</div> - </> - ); + useEffect(() => { + const url = `${import.meta.env.VITE_API_TITLE}/api/v1/article/${id}`; + fetch(url) + .then((response) => { + if (response.ok) { + return response.json(); + } + throw new Error("Network response was not ok."); + }) + .then((response) => setArticleData(response)); //.catch(() => navigate("/")); + }, [id]); + return ( + <> + <h1>{articleData?.title}</h1> + <div>{articleData?.content}</div> + </> + ); } diff --git a/frontend/src/pages/articles/New.tsx b/frontend/src/pages/articles/New.tsx index 3402f22..f98c19a 100644 --- a/frontend/src/pages/articles/New.tsx +++ b/frontend/src/pages/articles/New.tsx @@ -1,83 +1,100 @@ import { FormEvent } from "react"; import { useNavigate } from "react-router-dom"; -export default function NewArticle () { - const navigate = useNavigate(); +export default function NewArticle() { + const navigate = useNavigate(); - const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { - e.preventDefault(); //stops submit from happening + const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { + e.preventDefault(); //stops submit from happening - const target = e.target as typeof e.target & { - title: { value: string }; - photoUrl: { value: string }; - content: { value: string }; - }; + const target = e.target as typeof e.target & { + title: { value: string }; + photoUrl: { value: string }; + content: { value: string }; + }; - const formData = new FormData(); - formData.append('title', target.title.value); - formData.append('photoUrl', target.photoUrl.value); - formData.append('content', target.content.value); + const formData = new FormData(); + formData.append("title", target.title.value); + formData.append("photoUrl", target.photoUrl.value); + formData.append("content", target.content.value); - const response = await fetch(`${import.meta.env.VITE_API_TITLE}/api/v1/article/new`, { - credentials: 'include', - method: 'post', - body: formData, - }); - if(response.ok) { - navigate("/"); - } - else { - console.log(response); - alert("check console for error"); - } - }; - return( - <> -<div className="flex 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"> + const response = await fetch( + `${import.meta.env.VITE_API_TITLE}/api/v1/article/new`, + { + credentials: "include", + method: "post", + body: formData, + }, + ); + if (response.ok) { + navigate("/"); + } else { + console.log(response); + alert("check console for error"); + } + }; + return ( + <> + <div className="flex 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 border-red-500 rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" - id="title" - type="text" - name="title" - placeholder="Yep"/> - <p className="text-red-500 text-xs italic">Please fill out this field.</p> - </div> - <div className="w-full md:w-1/2 px-3"> - <label className="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"> + </label> + <input + className="appearance-none block w-full bg-gray-200 text-gray-700 border border-red-500 rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" + id="title" + type="text" + name="title" + placeholder="Yep" + /> + <p className="text-red-500 text-xs italic"> + Please fill out this field. + </p> + </div> + <div className="w-full md:w-1/2 px-3"> + <label className="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"> Photo URL - </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="photoUrl" - type="text" - name="photoUrl" - placeholder="Doe"/> - <p className="text-red-500 text-xs italic">Please fill out this field.</p> - </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"> + </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="photoUrl" + type="text" + name="photoUrl" + placeholder="Doe" + /> + <p className="text-red-500 text-xs italic"> + Please fill out this field. + </p> + </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"> Content - </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="content" - type="text" - name="content" - placeholder="Doe"/> - <p className="text-red-500 text-xs italic">Please fill out this field.</p> - </div> - </div> - <div className="flex flex-wrap mb-2"> - </div> - <button type="submit" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Create</button> - -</form> -</div> - </> - ); + </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="content" + type="text" + name="content" + placeholder="Doe" + /> + <p className="text-red-500 text-xs italic"> + Please fill out this field. + </p> + </div> + </div> + <div className="flex flex-wrap mb-2"></div> + <button + type="submit" + className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" + > + Create + </button> + </form> + </div> + </> + ); } diff --git a/frontend/src/pages/auth/Login.tsx b/frontend/src/pages/auth/Login.tsx index d064acf..33529a8 100644 --- a/frontend/src/pages/auth/Login.tsx +++ b/frontend/src/pages/auth/Login.tsx @@ -3,102 +3,103 @@ 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; + set: React.Dispatch<React.SetStateAction<string | null>>; + value: string | null; }; export default function Login({ user }: { user: user }) { - const navigate = useNavigate(); + const navigate = useNavigate(); - const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { - e.preventDefault(); //stops submit from happening + const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { + e.preventDefault(); //stops submit from happening - const target = e.target as typeof e.target & { - username: { value: string }; - email: { value: string }; - password: { value: string }; - }; + const target = e.target as typeof e.target & { + username: { value: string }; + email: { value: string }; + password: { value: string }; + }; - const formData = new FormData(); - formData.append("username", target.username.value); - formData.append("password", target.password.value); + const formData = new FormData(); + 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 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 { - console.log(response); - alert("check console for error"); - } - }); - }; + 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 { + console.log(response); + alert("check console for error"); + } + }); + }; - 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> - </> - ); + 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> + </> + ); } diff --git a/frontend/src/pages/auth/Register.tsx b/frontend/src/pages/auth/Register.tsx index 14ceea4..cf1972a 100644 --- a/frontend/src/pages/auth/Register.tsx +++ b/frontend/src/pages/auth/Register.tsx @@ -1,86 +1,103 @@ import { FormEvent } from "react"; -import { useNavigate } from 'react-router-dom'; +import { useNavigate } from "react-router-dom"; -export default function Register () { - const navigate = useNavigate(); +export default function Register() { + const navigate = useNavigate(); -const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { - e.preventDefault(); //stops submit from happening + const handleSubmit = async (e: FormEvent<HTMLFormElement>) => { + e.preventDefault(); //stops submit from happening - const target = e.target as typeof e.target & { - username: { value: string }; - email: { value: string }; - password: { value: string }; - }; + const target = e.target as typeof e.target & { + username: { value: string }; + email: { value: string }; + password: { value: string }; + }; - const formData = new FormData(); - formData.append('username', target.username.value); - formData.append('email', target.email.value); - formData.append('password', target.password.value); + const formData = new FormData(); + formData.append("username", target.username.value); + formData.append("email", target.email.value); + formData.append("password", target.password.value); - const response = await fetch(`${import.meta.env.VITE_API_TITLE}/api/v1/register`, { - credentials: 'include', - method: 'post', - body: formData, - }); - if(response.ok) { - navigate("/login"); - } - else { - alert("error"); - } - }; + const response = await fetch( + `${import.meta.env.VITE_API_TITLE}/api/v1/register`, + { + credentials: "include", + method: "post", + body: formData, + }, + ); + if (response.ok) { + navigate("/login"); + } else { + alert("error"); + } + }; - return( - <> -<div className="flex flex-col items-center justify-center bg-white p-12"> - <div className="text-xl w-full text-center mb-8 p-4 bg-black text-red-500">Username or Email already exists</div> - <form onSubmit={handleSubmit} method="post" className="w-full max-w-lg"> - <div className="flex flex-wrap -mx-3 mb-6"> + return ( + <> + <div className="flex flex-col items-center justify-center bg-white p-12"> + <div className="text-xl w-full text-center mb-8 p-4 bg-black text-red-500"> + Username or Email already exists + </div> + <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"/> - <p className="text-red-500 text-xs italic">Please fill out this field.</p> + <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" + /> + <p className="text-red-500 text-xs italic"> + Please fill out this field. + </p> </div> <div className="w-full md:w-1/2 px-3"> - <label className="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"> - Email - </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="email" - type="text" - name="email" - placeholder="[email protected]"/> - <p className="text-red-500 text-xs italic">Please fill out this field.</p> + <label className="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2"> + Email + </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="email" + type="text" + name="email" + placeholder="[email protected]" + /> + <p className="text-red-500 text-xs italic"> + Please fill out this field. + </p> </div> - </div> - <div className="flex flex-wrap -mx-3 mb-6"> + </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"/> - <p className="text-red-500 text-xs italic">Please fill out this field.</p> + <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" + /> + <p className="text-red-500 text-xs italic"> + Please fill out this field. + </p> </div> - </div> - <div className="flex flex-wrap mb-2"> - </div> - <button type="submit" className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">Register</button> - - </form> -</div> - </> - ); - + </div> + <div className="flex flex-wrap mb-2"></div> + <button + type="submit" + className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded" + > + Register + </button> + </form> + </div> + </> + ); } diff --git a/frontend/src/routes/index.tsx b/frontend/src/routes/index.tsx index b46315b..cee3529 100644 --- a/frontend/src/routes/index.tsx +++ b/frontend/src/routes/index.tsx @@ -8,36 +8,39 @@ import Register from "../pages/auth/Register"; import Login from "../pages/auth/Login"; type user = { - set: React.Dispatch<React.SetStateAction<string | null>>; - value: string | null; + set: React.Dispatch<React.SetStateAction<string | null>>; + value: string | null; }; type articleSearch = user; export default function Index() { - const [user, setUser] = useState<string | null>(null); - const [articleSearch, setArticleSearch] = useState<string | null>(null); + const [user, setUser] = useState<string | null>(null); + const [articleSearch, setArticleSearch] = useState<string | null>(null); - const userProp: user = { set: setUser, value: user }; - const articleSearchProp: articleSearch = { - set: setArticleSearch, - value: articleSearch, - }; + const userProp: user = { set: setUser, value: user }; + const articleSearchProp: articleSearch = { + set: setArticleSearch, + value: articleSearch, + }; - return ( - <> - <Router> - <Routes> - <Route - path="/" - element={<Layout user={userProp} articleSearch={articleSearchProp} />}> - <Route index element={<Home articleSearch={articleSearchProp} />} /> - <Route path="/article/:id" element={<Article />} /> - <Route path="/article/new" element={<NewArticle />} /> - <Route path="register" element={<Register />} /> - <Route path="login" element={<Login user={userProp} />} /> - </Route> - </Routes> - </Router> - </> - ); + return ( + <> + <Router> + <Routes> + <Route + path="/" + element={ + <Layout user={userProp} articleSearch={articleSearchProp} /> + } + > + <Route index element={<Home articleSearch={articleSearchProp} />} /> + <Route path="/article/:id" element={<Article />} /> + <Route path="/article/new" element={<NewArticle />} /> + <Route path="register" element={<Register />} /> + <Route path="login" element={<Login user={userProp} />} /> + </Route> + </Routes> + </Router> + </> + ); } diff --git a/frontend/tailwind.config.js b/frontend/tailwind.config.js index d37737f..614c86b 100644 --- a/frontend/tailwind.config.js +++ b/frontend/tailwind.config.js @@ -1,12 +1,8 @@ /** @type {import('tailwindcss').Config} */ export default { - content: [ - "./index.html", - "./src/**/*.{js,ts,jsx,tsx}", - ], + content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"], theme: { extend: {}, }, plugins: [], -} - +}; diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 861b04b..d366e8c 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,7 +1,7 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react-swc' +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react-swc"; // https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], -}) +}); |
