Begin navbar
This commit is contained in:
parent
41a21ee0b5
commit
3b2258877f
@ -4,6 +4,7 @@ import styles from '../styles/Dashboard.module.css';
|
|||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||||
import { faTrash } from '@fortawesome/free-solid-svg-icons';
|
import { faTrash } from '@fortawesome/free-solid-svg-icons';
|
||||||
|
import Navbar from './Navbar';
|
||||||
|
|
||||||
function Dashboard() {
|
function Dashboard() {
|
||||||
document.title = 'LinkLogger | Dashboard';
|
document.title = 'LinkLogger | Dashboard';
|
||||||
@ -44,10 +45,15 @@ function Dashboard() {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// Catch 404 error = user has no links
|
.catch((error: unknown) => {
|
||||||
|
if (axios.isAxiosError(error)) {
|
||||||
.catch(() => {
|
if (error.response?.status === 404) {
|
||||||
navigate('/login');
|
// Create a message alerting the user there are no links
|
||||||
|
navigate('/login');
|
||||||
|
} else {
|
||||||
|
navigate('/login');
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
@ -109,79 +115,82 @@ function Dashboard() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<table id={styles.mainTable}>
|
<>
|
||||||
<thead>
|
<Navbar />
|
||||||
<tr style={{ border: '2px solid #ccc' }}>
|
<table id={styles.mainTable}>
|
||||||
<th>Link</th>
|
<thead>
|
||||||
<th>Visits</th>
|
<tr style={{ border: '2px solid #ccc' }}>
|
||||||
<th>Redirect</th>
|
<th>Link</th>
|
||||||
<th>Expire Date</th>
|
<th>Visits</th>
|
||||||
</tr>
|
<th>Redirect</th>
|
||||||
</thead>
|
<th>Expire Date</th>
|
||||||
<tbody>
|
</tr>
|
||||||
{/* For every link and its logs */}
|
</thead>
|
||||||
{links.map((link) => (
|
<tbody>
|
||||||
<React.Fragment key={link.link}>
|
{/* For every link and its logs */}
|
||||||
<tr className={styles.linkTableRow}>
|
{links.map((link) => (
|
||||||
<td>
|
<React.Fragment key={link.link}>
|
||||||
<button
|
<tr className={styles.linkTableRow}>
|
||||||
onClick={() => toggleLogRow(link.link)}
|
<td>
|
||||||
className={styles.linkButton}
|
<button
|
||||||
>
|
onClick={() => toggleLogRow(link.link)}
|
||||||
{link.link}
|
className={styles.linkButton}
|
||||||
</button>
|
>
|
||||||
</td>
|
{link.link}
|
||||||
<td>
|
</button>
|
||||||
{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>
|
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{logs.filter((log) => log.link === link.link).length || 0}
|
||||||
|
</td>
|
||||||
|
<td>{link.redirect_link}</td>
|
||||||
|
<td>{link.expire_date}</td>
|
||||||
</tr>
|
</tr>
|
||||||
)}
|
|
||||||
</React.Fragment>
|
{/* Conditionally render logs for this link */}
|
||||||
))}
|
{visibleLog === link.link && (
|
||||||
</tbody>
|
<tr className={styles.logTableRow}>
|
||||||
</table>
|
<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>
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,7 @@ import styles from '../styles/Login.module.css';
|
|||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import axios from 'axios';
|
import axios from 'axios';
|
||||||
|
import Navbar from './Navbar';
|
||||||
|
|
||||||
function Login() {
|
function Login() {
|
||||||
document.title = 'LinkLogger | Login';
|
document.title = 'LinkLogger | Login';
|
||||||
@ -48,43 +49,46 @@ function Login() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div id={styles.container}>
|
<>
|
||||||
<p id={styles.loginText}>Log In</p>
|
<Navbar />
|
||||||
<p id={styles.error} className={error ? 'visible' : 'hidden'}>
|
<div id={styles.container}>
|
||||||
{error}
|
<p id={styles.loginText}>Log In</p>
|
||||||
</p>
|
<p id={styles.error} className={error ? 'visible' : 'hidden'}>
|
||||||
<div>
|
{error}
|
||||||
<header>
|
</p>
|
||||||
<hr></hr>
|
<div>
|
||||||
<form onSubmit={handleSubmit}>
|
<header>
|
||||||
<input
|
<hr></hr>
|
||||||
type="text"
|
<form onSubmit={handleSubmit}>
|
||||||
placeholder="username"
|
<input
|
||||||
value={username}
|
type="text"
|
||||||
onChange={(e) => setUsername(e.target.value)}
|
placeholder="username"
|
||||||
required
|
value={username}
|
||||||
/>
|
onChange={(e) => setUsername(e.target.value)}
|
||||||
<input
|
required
|
||||||
type="password"
|
/>
|
||||||
placeholder="password"
|
<input
|
||||||
value={password}
|
type="password"
|
||||||
onChange={(e) => setPassword(e.target.value)}
|
placeholder="password"
|
||||||
required
|
value={password}
|
||||||
/>
|
onChange={(e) => setPassword(e.target.value)}
|
||||||
<button type="submit" disabled={isSubmitting}>
|
required
|
||||||
{isSubmitting ? 'Submitting...' : 'Submit'}
|
/>
|
||||||
</button>
|
<button type="submit" disabled={isSubmitting}>
|
||||||
</form>
|
{isSubmitting ? 'Submitting...' : 'Submit'}
|
||||||
<hr></hr>
|
</button>
|
||||||
<p id={styles.bottomText}>
|
</form>
|
||||||
Don't have an account?{' '}
|
<hr></hr>
|
||||||
<Link to="/signup" className={styles.link}>
|
<p id={styles.bottomText}>
|
||||||
Create one now
|
Don't have an account?{' '}
|
||||||
</Link>
|
<Link to="/signup" className={styles.link}>
|
||||||
</p>
|
Create one now
|
||||||
</header>
|
</Link>
|
||||||
|
</p>
|
||||||
|
</header>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
11
app/src/components/Navbar.tsx
Normal file
11
app/src/components/Navbar.tsx
Normal 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;
|
18
app/src/styles/Navbar.module.css
Normal file
18
app/src/styles/Navbar.module.css
Normal 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;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user