Update UI

This commit is contained in:
Parker M. 2024-11-13 22:45:57 -06:00
parent 9ce608b637
commit dbc53a555e
Signed by: parker
GPG Key ID: 505ED36FC12B5D5E
7 changed files with 201 additions and 152 deletions

View File

@ -47,10 +47,7 @@ function Dashboard() {
.catch((error: unknown) => { .catch((error: unknown) => {
if (axios.isAxiosError(error)) { if (axios.isAxiosError(error)) {
if (error.response?.status === 404) { if (error.response?.status != 404) {
// Create a message alerting the user there are no links
navigate('/login');
} else {
navigate('/login'); navigate('/login');
} }
} }
@ -68,11 +65,12 @@ function Dashboard() {
navigate('/login'); navigate('/login');
} }
}) })
.catch((error: unknown) => {
// Catch 404 error = user has no logs if (axios.isAxiosError(error)) {
if (error.response?.status != 404) {
.catch(() => { navigate('/login');
navigate('/login'); }
}
}); });
}, []); }, []);
@ -117,7 +115,7 @@ function Dashboard() {
return ( return (
<> <>
<Navbar /> <Navbar />
<table id={styles.mainTable}> <table className={styles.mainTable}>
<thead> <thead>
<tr style={{ border: '2px solid #ccc' }}> <tr style={{ border: '2px solid #ccc' }}>
<th>Link</th> <th>Link</th>
@ -127,6 +125,17 @@ function Dashboard() {
</tr> </tr>
</thead> </thead>
<tbody> <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 */} {/* For every link and its logs */}
{links.map((link) => ( {links.map((link) => (
<React.Fragment key={link.link}> <React.Fragment key={link.link}>
@ -161,7 +170,7 @@ function Dashboard() {
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
{/* Render logs only if visibleLog matches the link */} {/* Render all logs for the link */}
{logs {logs
.filter((log) => log.link === link.link) .filter((log) => log.link === link.link)
.map((log, index, filteredLogs) => ( .map((log, index, filteredLogs) => (
@ -181,6 +190,17 @@ function Dashboard() {
</td> </td>
</tr> </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> </tbody>
</table> </table>
</td> </td>

View File

@ -1,5 +1,5 @@
import { useState, FormEvent } from 'react'; 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 { 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';
@ -51,42 +51,36 @@ function Login() {
return ( return (
<> <>
<Navbar /> <Navbar />
<div id={styles.container}> <div className={styles.container}>
<p id={styles.loginText}>Log In</p> <h1>Log In</h1>
<p id={styles.error} className={error ? 'visible' : 'hidden'}> <h2 className={error ? 'errorVisible' : 'errorHidden'}>{error}</h2>
{error} <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> </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

@ -1,21 +1,63 @@
import { useState, useEffect } from 'react';
import styles from '../styles/Navbar.module.css'; import styles from '../styles/Navbar.module.css';
import { Link } from 'react-router-dom'; import { Link } from 'react-router-dom';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faCircleUp, faCircleDown } from '@fortawesome/free-solid-svg-icons';
function Navbar() { 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 ( return (
<div className={styles.navbar}> <div className={styles.navbar}>
<div className={styles.navbarLeft}> <div className={styles.left}>
<Link to={'/login'}> <Link to={'/login'}>
<a className={styles.navbarLink}>Login</a> <a className={styles.link}>Login</a>
</Link> </Link>
<Link to={'/signup'}> <Link to={'/signup'}>
<a className={styles.navbarLink}>Signup</a> <a className={styles.link}>Signup</a>
</Link> </Link>
</div> </div>
<div className={styles.navbarRight}> <div className={styles.right}>
<Link to={'/status'}> <a
<a className={styles.navbarLink}>API Status</a> className={styles.link}
</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>
</div> </div>
); );

View File

@ -1,5 +1,5 @@
import { useState, FormEvent } from 'react'; 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 { 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';
@ -64,51 +64,45 @@ function Signup() {
return ( return (
<> <>
<Navbar /> <Navbar />
<div id={styles.container}> <div className={styles.container}>
<p id={styles.signupText}>Sign up</p> <h1>Sign up</h1>
<p id={styles.error} className={error ? 'visible' : 'hidden'}> <h2 className={error ? 'errorVisible' : 'errorHidden'}>{error}</h2>
{error} <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> </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> </div>
</> </>
); );

View File

@ -5,7 +5,7 @@ body {
background-color: #2c3338; background-color: #2c3338;
} }
#container { .container {
font-size: 17px; font-size: 17px;
position: absolute; position: absolute;
top: 50%; top: 50%;
@ -14,8 +14,7 @@ body {
text-align: center; text-align: center;
} }
#loginText, h1 {
#signupText {
color: #ccc; color: #ccc;
font-size: 30px; font-size: 30px;
font-weight: 600; font-weight: 600;
@ -59,29 +58,26 @@ button:active {
transform: scale(0.95); transform: scale(0.95);
} }
#error { .errorVisible {
visibility: visible;
color: #ee6161; color: #ee6161;
} }
.link { .errorHidden {
text-decoration: underline; visibility: hidden;
color: #ccc; color: #ee6161;
} }
.link:hover { .footnoteLink {
text-decoration: underline;
color: #ccc;
}
.footnoteLink:hover {
text-decoration: none; text-decoration: none;
color: #415eac; color: #415eac;
} }
#bottomText { .footnote {
color: #606468; color: #606468;
}
.visible {
visibility: visible;
}
.hidden {
visibility: hidden;
} }

View File

@ -5,13 +5,6 @@ body {
background-color: #2c3338; background-color: #2c3338;
} }
#mainTable {
position: absolute;
top: 100px;
left: 50%;
transform: translateX(-50%);
}
table { table {
margin: 0 auto; margin: 0 auto;
text-align: center; text-align: center;
@ -22,42 +15,31 @@ table {
overflow: hidden; overflow: hidden;
} }
/* Center all sub tables */
.logTableRow table {
margin: 0 auto;
}
.logTableRow table {
width: 90%;
}
table th { table th {
background-color: #415eac; background-color: #415eac;
border: 2px solid #ccc; border: 2px solid #ccc;
padding: 10px; padding: 10px;
} }
.linkTableRow {
border: 2px solid #ccc;
}
table td { table td {
padding: 10px; padding: 10px;
} }
.mainTable {
position: absolute;
top: 100px;
left: 50%;
transform: translateX(-50%);
}
.linkTableRow {
border: 2px solid #ccc;
}
.linkTableRow td { .linkTableRow td {
padding: 20px; padding: 20px;
} }
.logTableRow table td {
background-color: #3b4148;
padding: 10px;
}
.logTableRow table tr {
border: 2px solid #ccc;
}
.linkButton { .linkButton {
background-color: #3b4148; background-color: #3b4148;
color: #ccc; color: #ccc;
@ -68,6 +50,20 @@ table td {
border-radius: 5px; 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 { .trashBin:hover {
color: rgb(238, 86, 86); color: rgb(238, 86, 86);
cursor: pointer; cursor: pointer;

View File

@ -1,4 +1,3 @@
/* Create the navbar and set the colors */
.navbar { .navbar {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
@ -7,7 +6,7 @@
padding: 15px; padding: 15px;
} }
.navbarLink { .link {
margin: 0 20px; margin: 0 20px;
position: relative; position: relative;
display: inline-block; display: inline-block;
@ -17,7 +16,7 @@
font-weight: 600; font-weight: 600;
} }
.navbarLink::after { .link::after {
content: ""; content: "";
position: absolute; position: absolute;
bottom: 0; bottom: 0;
@ -28,14 +27,22 @@
transition: width 0.3s ease; transition: width 0.3s ease;
} }
.navbarLink:hover::after { .link:hover::after {
width: 100%; width: 100%;
} }
.navbarLeft { .circleUp {
color: rgb(122, 224, 122);
}
.circleDown {
color: rgb(218, 112, 112);
}
.left {
margin-left: 50px; margin-left: 50px;
} }
.navbarRight { .right {
margin-right: 50px; margin-right: 50px;
} }