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) => {
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>

View File

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

View File

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

View File

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

View File

@ -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;
}
.link {
text-decoration: underline;
color: #ccc;
.errorHidden {
visibility: hidden;
color: #ee6161;
}
.link:hover {
.footnoteLink {
text-decoration: underline;
color: #ccc;
}
.footnoteLink:hover {
text-decoration: none;
color: #415eac;
}
#bottomText {
.footnote {
color: #606468;
}
.visible {
visibility: visible;
}
.hidden {
visibility: hidden;
}

View File

@ -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,42 +15,31 @@ 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;
}
.mainTable {
position: absolute;
top: 100px;
left: 50%;
transform: translateX(-50%);
}
.linkTableRow {
border: 2px solid #ccc;
}
.linkTableRow td {
padding: 20px;
}
.logTableRow table td {
background-color: #3b4148;
padding: 10px;
}
.logTableRow table tr {
border: 2px solid #ccc;
}
.linkButton {
background-color: #3b4148;
color: #ccc;
@ -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;

View File

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