diff options
author | Parker <contact@pkrm.dev> | 2024-11-12 16:37:28 -0600 |
---|---|---|
committer | Parker <contact@pkrm.dev> | 2024-11-12 16:37:28 -0600 |
commit | 3b2258877fcbd211314b153c56273e3a597ad08b (patch) | |
tree | 28fddd745f436ab70a9f29ad486d5a6d38b2ebbb | |
parent | 41a21ee0b597d971169d5ce4e19f86a1248dbf96 (diff) |
Begin navbar
-rw-r--r-- | app/src/components/Dashboard.tsx | 159 | ||||
-rw-r--r-- | app/src/components/Login.tsx | 76 | ||||
-rw-r--r-- | app/src/components/Navbar.tsx | 11 | ||||
-rw-r--r-- | app/src/styles/Navbar.module.css | 18 |
4 files changed, 153 insertions, 111 deletions
diff --git a/app/src/components/Dashboard.tsx b/app/src/components/Dashboard.tsx index 51d3020..e16c44e 100644 --- a/app/src/components/Dashboard.tsx +++ b/app/src/components/Dashboard.tsx @@ -4,6 +4,7 @@ import styles from '../styles/Dashboard.module.css'; import { useNavigate } from 'react-router-dom'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faTrash } from '@fortawesome/free-solid-svg-icons'; +import Navbar from './Navbar'; function Dashboard() { document.title = 'LinkLogger | Dashboard'; @@ -44,10 +45,15 @@ function Dashboard() { } }) - // Catch 404 error = user has no links - - .catch(() => { - navigate('/login'); + .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 { + navigate('/login'); + } + } }); }, []); @@ -109,79 +115,82 @@ function Dashboard() { }; return ( - <table id={styles.mainTable}> - <thead> - <tr style={{ border: '2px solid #ccc' }}> - <th>Link</th> - <th>Visits</th> - <th>Redirect</th> - <th>Expire Date</th> - </tr> - </thead> - <tbody> - {/* For every link and its logs */} - {links.map((link) => ( - <React.Fragment key={link.link}> - <tr className={styles.linkTableRow}> - <td> - <button - onClick={() => toggleLogRow(link.link)} - className={styles.linkButton} - > - {link.link} - </button> - </td> - <td> - {logs.filter((log) => log.link === link.link).length || 0} - </td> - <td>{link.redirect_link}</td> - <td>{link.expire_date}</td> - </tr> - - {/* Conditionally render logs for this link */} - {visibleLog === link.link && ( - <tr className={styles.logTableRow}> - <td colSpan={6}> - <table> - <thead> - <tr> - <th>ID</th> - <th>Timestamp</th> - <th>IP</th> - <th>Location</th> - <th colSpan={2}>ISP</th> - </tr> - </thead> - <tbody> - {/* Render logs only if visibleLog matches the link */} - {logs - .filter((log) => log.link === link.link) - .map((log, index, filteredLogs) => ( - <tr key={log.id}> - <td>{filteredLogs.length - index}</td> - <td>{log.timestamp}</td> - <td>{log.ip}</td> - <td>{log.location}</td> - <td>{log.isp}</td> - <td> - <FontAwesomeIcon - icon={faTrash} - className={styles.trashBin} - id={log.id.toString()} - onClick={deleteLog} - /> - </td> - </tr> - ))} - </tbody> - </table> + <> + <Navbar /> + <table id={styles.mainTable}> + <thead> + <tr style={{ border: '2px solid #ccc' }}> + <th>Link</th> + <th>Visits</th> + <th>Redirect</th> + <th>Expire Date</th> + </tr> + </thead> + <tbody> + {/* For every link and its logs */} + {links.map((link) => ( + <React.Fragment key={link.link}> + <tr className={styles.linkTableRow}> + <td> + <button + onClick={() => toggleLogRow(link.link)} + className={styles.linkButton} + > + {link.link} + </button> + </td> + <td> + {logs.filter((log) => log.link === link.link).length || 0} </td> + <td>{link.redirect_link}</td> + <td>{link.expire_date}</td> </tr> - )} - </React.Fragment> - ))} - </tbody> - </table> + + {/* Conditionally render logs for this link */} + {visibleLog === link.link && ( + <tr className={styles.logTableRow}> + <td colSpan={6}> + <table> + <thead> + <tr> + <th>ID</th> + <th>Timestamp</th> + <th>IP</th> + <th>Location</th> + <th colSpan={2}>ISP</th> + </tr> + </thead> + <tbody> + {/* Render logs only if visibleLog matches the link */} + {logs + .filter((log) => log.link === link.link) + .map((log, index, filteredLogs) => ( + <tr key={log.id}> + <td>{filteredLogs.length - index}</td> + <td>{log.timestamp}</td> + <td>{log.ip}</td> + <td>{log.location}</td> + <td>{log.isp}</td> + <td> + <FontAwesomeIcon + icon={faTrash} + className={styles.trashBin} + id={log.id.toString()} + onClick={deleteLog} + /> + </td> + </tr> + ))} + </tbody> + </table> + </td> + </tr> + )} + </React.Fragment> + ))} + </tbody> + </table> + </> ); } diff --git a/app/src/components/Login.tsx b/app/src/components/Login.tsx index 2a81295..807face 100644 --- a/app/src/components/Login.tsx +++ b/app/src/components/Login.tsx @@ -3,6 +3,7 @@ import styles from '../styles/Login.module.css'; import { Link } from 'react-router-dom'; import { useNavigate } from 'react-router-dom'; import axios from 'axios'; +import Navbar from './Navbar'; function Login() { document.title = 'LinkLogger | Login'; @@ -48,43 +49,46 @@ function Login() { }; return ( - <div id={styles.container}> - <p id={styles.loginText}>Log In</p> - <p id={styles.error} className={error ? 'visible' : 'hidden'}> - {error} - </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> + <> + <Navbar /> + <div id={styles.container}> + <p id={styles.loginText}>Log In</p> + <p id={styles.error} className={error ? 'visible' : 'hidden'}> + {error} + </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> - </div> + </> ); } diff --git a/app/src/components/Navbar.tsx b/app/src/components/Navbar.tsx new file mode 100644 index 0000000..7ffb514 --- /dev/null +++ b/app/src/components/Navbar.tsx @@ -0,0 +1,11 @@ +import styles from '../styles/Navbar.module.css'; + +function Navbar() { + return ( + <nav className={styles.navbar}> + <span>LinkLogger</span> + </nav> + ); +} + +export default Navbar; diff --git a/app/src/styles/Navbar.module.css b/app/src/styles/Navbar.module.css new file mode 100644 index 0000000..217e4b1 --- /dev/null +++ b/app/src/styles/Navbar.module.css @@ -0,0 +1,18 @@ +/* Create the nav and center the span */ +.navbar { + display: flex; + justify-content: center; + align-items: center; + height: 60px; + background-color: #f8f9fa; +} + +/* Create the nav links */ + +span { + font-size: 35px; + font-weight: 600; + color: #333; + text-decoration: none; + margin-right: 10px; +}
\ No newline at end of file |