diff options
author | Parker <contact@pkrm.dev> | 2024-11-13 22:45:57 -0600 |
---|---|---|
committer | Parker <contact@pkrm.dev> | 2024-11-13 22:45:57 -0600 |
commit | dbc53a555e64fdd0b848bf33b4208820b8701509 (patch) | |
tree | 9b89e5fc4a3fce4c68114010da6e3bb61b25d027 | |
parent | 9ce608b637f3ade7346afbaf2bdd1dbf0a8767f7 (diff) |
Update UI
-rw-r--r-- | app/src/components/Dashboard.tsx | 42 | ||||
-rw-r--r-- | app/src/components/Login.tsx | 66 | ||||
-rw-r--r-- | app/src/components/Navbar.tsx | 56 | ||||
-rw-r--r-- | app/src/components/Signup.tsx | 84 | ||||
-rw-r--r-- | app/src/styles/Auth.module.css (renamed from app/src/styles/Login.module.css) | 28 | ||||
-rw-r--r-- | app/src/styles/Dashboard.module.css | 50 | ||||
-rw-r--r-- | app/src/styles/Navbar.module.css | 19 |
7 files changed, 197 insertions, 148 deletions
diff --git a/app/src/components/Dashboard.tsx b/app/src/components/Dashboard.tsx index e16c44e..f3442e0 100644 --- a/app/src/components/Dashboard.tsx +++ b/app/src/components/Dashboard.tsx @@ -47,10 +47,7 @@ function Dashboard() { .catch((error: unknown) => { if (axios.isAxiosError(error)) { - if (error.response?.status === 404) { - // Create a message alerting the user there are no links - navigate('/login'); - } else { + if (error.response?.status != 404) { navigate('/login'); } } @@ -68,11 +65,12 @@ function Dashboard() { navigate('/login'); } }) - - // Catch 404 error = user has no logs - - .catch(() => { - navigate('/login'); + .catch((error: unknown) => { + if (axios.isAxiosError(error)) { + if (error.response?.status != 404) { + navigate('/login'); + } + } }); }, []); @@ -117,7 +115,7 @@ function Dashboard() { return ( <> <Navbar /> - <table id={styles.mainTable}> + <table className={styles.mainTable}> <thead> <tr style={{ border: '2px solid #ccc' }}> <th>Link</th> @@ -127,6 +125,17 @@ function Dashboard() { </tr> </thead> <tbody> + {/* If there are no links, put a special message */} + {links.length === 0 && ( + <tr> + <td colSpan={4}> + <div className={styles.noLinks}> + You do not have any shortened links - try creating one. + </div> + </td> + </tr> + )} + {/* For every link and its logs */} {links.map((link) => ( <React.Fragment key={link.link}> @@ -161,7 +170,7 @@ function Dashboard() { </tr> </thead> <tbody> - {/* Render logs only if visibleLog matches the link */} + {/* Render all logs for the link */} {logs .filter((log) => log.link === link.link) .map((log, index, filteredLogs) => ( @@ -181,6 +190,17 @@ function Dashboard() { </td> </tr> ))} + {/* If the link has no logs, put a special message */} + {logs.filter((log) => log.link === link.link).length === + 0 && ( + <tr> + <td colSpan={6}> + <div className={styles.noLogs}> + No logs for this link + </div> + </td> + </tr> + )} </tbody> </table> </td> diff --git a/app/src/components/Login.tsx b/app/src/components/Login.tsx index 807face..badb5b1 100644 --- a/app/src/components/Login.tsx +++ b/app/src/components/Login.tsx @@ -1,5 +1,5 @@ import { useState, FormEvent } from 'react'; -import styles from '../styles/Login.module.css'; +import styles from '../styles/Auth.module.css'; import { Link } from 'react-router-dom'; import { useNavigate } from 'react-router-dom'; import axios from 'axios'; @@ -51,42 +51,36 @@ function Login() { return ( <> <Navbar /> - <div id={styles.container}> - <p id={styles.loginText}>Log In</p> - <p id={styles.error} className={error ? 'visible' : 'hidden'}> - {error} + <div className={styles.container}> + <h1>Log In</h1> + <h2 className={error ? 'errorVisible' : 'errorHidden'}>{error}</h2> + <hr></hr> + <form onSubmit={handleSubmit}> + <input + type="text" + placeholder="username" + value={username} + onChange={(e) => setUsername(e.target.value)} + required + /> + <input + type="password" + placeholder="password" + value={password} + onChange={(e) => setPassword(e.target.value)} + required + /> + <button type="submit" disabled={isSubmitting}> + {isSubmitting ? 'Submitting...' : 'Submit'} + </button> + </form> + <hr></hr> + <p className={styles.footnote}> + Don't have an account?{' '} + <Link to="/signup" className={styles.footnoteLink}> + Create one now + </Link> </p> - <div> - <header> - <hr></hr> - <form onSubmit={handleSubmit}> - <input - type="text" - placeholder="username" - value={username} - onChange={(e) => setUsername(e.target.value)} - required - /> - <input - type="password" - placeholder="password" - value={password} - onChange={(e) => setPassword(e.target.value)} - required - /> - <button type="submit" disabled={isSubmitting}> - {isSubmitting ? 'Submitting...' : 'Submit'} - </button> - </form> - <hr></hr> - <p id={styles.bottomText}> - Don't have an account?{' '} - <Link to="/signup" className={styles.link}> - Create one now - </Link> - </p> - </header> - </div> </div> </> ); diff --git a/app/src/components/Navbar.tsx b/app/src/components/Navbar.tsx index 5107bf4..53c1f52 100644 --- a/app/src/components/Navbar.tsx +++ b/app/src/components/Navbar.tsx @@ -1,21 +1,63 @@ +import { useState, useEffect } from 'react'; import styles from '../styles/Navbar.module.css'; import { Link } from 'react-router-dom'; +import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; +import { faCircleUp, faCircleDown } from '@fortawesome/free-solid-svg-icons'; function Navbar() { + const [isOnline, setIsOnline] = useState<boolean | null>(null); + + useEffect(() => { + const checkAPIStatus = async () => { + try { + const res = await fetch('/api/ping'); + + if (res.status === 200) { + setIsOnline(true); + } else { + setIsOnline(false); + } + } catch (error) { + setIsOnline(false); + } + }; + + checkAPIStatus(); + }); + return ( <div className={styles.navbar}> - <div className={styles.navbarLeft}> + <div className={styles.left}> <Link to={'/login'}> - <a className={styles.navbarLink}>Login</a> + <a className={styles.link}>Login</a> </Link> <Link to={'/signup'}> - <a className={styles.navbarLink}>Signup</a> + <a className={styles.link}>Signup</a> </Link> </div> - <div className={styles.navbarRight}> - <Link to={'/status'}> - <a className={styles.navbarLink}>API Status</a> - </Link> + <div className={styles.right}> + <a + className={styles.link} + title={ + isOnline === null + ? 'Loading...' + : isOnline + ? 'API is online' + : 'API is offline' + } + > + API Status:{' '} + {isOnline === null ? ( + 'Loading...' + ) : isOnline ? ( + <FontAwesomeIcon icon={faCircleUp} className={styles.circleUp} /> + ) : ( + <FontAwesomeIcon + icon={faCircleDown} + className={styles.circleDown} + /> + )} + </a> </div> </div> ); diff --git a/app/src/components/Signup.tsx b/app/src/components/Signup.tsx index 5ec2e17..f4a3368 100644 --- a/app/src/components/Signup.tsx +++ b/app/src/components/Signup.tsx @@ -1,5 +1,5 @@ import { useState, FormEvent } from 'react'; -import styles from '../styles/Login.module.css'; +import styles from '../styles/Auth.module.css'; import { Link } from 'react-router-dom'; import { useNavigate } from 'react-router-dom'; import axios from 'axios'; @@ -64,51 +64,45 @@ function Signup() { return ( <> <Navbar /> - <div id={styles.container}> - <p id={styles.signupText}>Sign up</p> - <p id={styles.error} className={error ? 'visible' : 'hidden'}> - {error} + <div className={styles.container}> + <h1>Sign up</h1> + <h2 className={error ? 'errorVisible' : 'errorHidden'}>{error}</h2> + <hr></hr> + <form onSubmit={handleSubmit}> + <input + type="text" + placeholder="username" + value={username} + onChange={(e) => setUsername(e.target.value)} + required + /> + <input + type="password" + placeholder="password" + value={password} + minLength={8} + onChange={(e) => setPassword(e.target.value)} + required + /> + <input + type="password" + placeholder="confirm password" + value={passwordConfirm} + minLength={8} + onChange={(e) => setPasswordConfirm(e.target.value)} + required + /> + <button type="submit" disabled={isSubmitting}> + {isSubmitting ? 'Submitting...' : 'Submit'} + </button> + </form> + <hr></hr> + <p className={styles.footnote}> + Already have an account?{' '} + <Link to="/login" className={styles.footnoteLink}> + Log in here. + </Link> </p> - <div> - <header> - <hr></hr> - <form onSubmit={handleSubmit}> - <input - type="text" - placeholder="username" - value={username} - onChange={(e) => setUsername(e.target.value)} - required - /> - <input - type="password" - placeholder="password" - value={password} - minLength={8} - onChange={(e) => setPassword(e.target.value)} - required - /> - <input - type="password" - placeholder="confirm password" - value={passwordConfirm} - minLength={8} - onChange={(e) => setPasswordConfirm(e.target.value)} - required - /> - <button type="submit" disabled={isSubmitting}> - {isSubmitting ? 'Submitting...' : 'Submit'} - </button> - </form> - <hr></hr> - <p id={styles.bottomText}> - Already have an account?{' '} - <Link to="/login" className={styles.link}> - Log in here. - </Link> - </p> - </header> - </div> </div> </> ); diff --git a/app/src/styles/Login.module.css b/app/src/styles/Auth.module.css index b2bcddf..7e1d3e3 100644 --- a/app/src/styles/Login.module.css +++ b/app/src/styles/Auth.module.css @@ -5,7 +5,7 @@ body { background-color: #2c3338; } -#container { +.container { font-size: 17px; position: absolute; top: 50%; @@ -14,8 +14,7 @@ body { text-align: center; } -#loginText, -#signupText { +h1 { color: #ccc; font-size: 30px; font-weight: 600; @@ -59,29 +58,26 @@ button:active { transform: scale(0.95); } -#error { +.errorVisible { + visibility: visible; + color: #ee6161; +} + +.errorHidden { + visibility: hidden; color: #ee6161; } -.link { +.footnoteLink { text-decoration: underline; color: #ccc; - } -.link:hover { +.footnoteLink:hover { text-decoration: none; color: #415eac; } -#bottomText { +.footnote { color: #606468; -} - -.visible { - visibility: visible; -} - -.hidden { - visibility: hidden; }
\ No newline at end of file diff --git a/app/src/styles/Dashboard.module.css b/app/src/styles/Dashboard.module.css index ef6b451..96ed919 100644 --- a/app/src/styles/Dashboard.module.css +++ b/app/src/styles/Dashboard.module.css @@ -5,13 +5,6 @@ body { background-color: #2c3338; } -#mainTable { - position: absolute; - top: 100px; - left: 50%; - transform: translateX(-50%); -} - table { margin: 0 auto; text-align: center; @@ -22,40 +15,29 @@ table { overflow: hidden; } -/* Center all sub tables */ -.logTableRow table { - margin: 0 auto; -} - -.logTableRow table { - width: 90%; -} - table th { background-color: #415eac; border: 2px solid #ccc; padding: 10px; } -.linkTableRow { - border: 2px solid #ccc; -} - table td { padding: 10px; } -.linkTableRow td { - padding: 20px; +.mainTable { + position: absolute; + top: 100px; + left: 50%; + transform: translateX(-50%); } -.logTableRow table td { - background-color: #3b4148; - padding: 10px; +.linkTableRow { + border: 2px solid #ccc; } -.logTableRow table tr { - border: 2px solid #ccc; +.linkTableRow td { + padding: 20px; } .linkButton { @@ -68,6 +50,20 @@ table td { border-radius: 5px; } +.logTableRow table { + margin: 0 auto; + width: 90%; +} + +.logTableRow table td { + background-color: #3b4148; + padding: 10px; +} + +.logTableRow table tr { + border: 2px solid #ccc; +} + .trashBin:hover { color: rgb(238, 86, 86); cursor: pointer; diff --git a/app/src/styles/Navbar.module.css b/app/src/styles/Navbar.module.css index d8c3f72..09ad94c 100644 --- a/app/src/styles/Navbar.module.css +++ b/app/src/styles/Navbar.module.css @@ -1,4 +1,3 @@ -/* Create the navbar and set the colors */ .navbar { display: flex; justify-content: space-between; @@ -7,7 +6,7 @@ padding: 15px; } -.navbarLink { +.link { margin: 0 20px; position: relative; display: inline-block; @@ -17,7 +16,7 @@ font-weight: 600; } -.navbarLink::after { +.link::after { content: ""; position: absolute; bottom: 0; @@ -28,14 +27,22 @@ transition: width 0.3s ease; } -.navbarLink:hover::after { +.link:hover::after { width: 100%; } -.navbarLeft { +.circleUp { + color: rgb(122, 224, 122); +} + +.circleDown { + color: rgb(218, 112, 112); +} + +.left { margin-left: 50px; } -.navbarRight { +.right { margin-right: 50px; }
\ No newline at end of file |