Begin navbar

This commit is contained in:
Parker M. 2024-11-12 16:37:28 -06:00
parent 41a21ee0b5
commit 3b2258877f
Signed by: parker
GPG Key ID: 505ED36FC12B5D5E
4 changed files with 153 additions and 111 deletions

View File

@ -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>
</>
);
}

View File

@ -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>
</>
);
}

View File

@ -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;

View File

@ -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;
}