aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorParker <contact@pkrm.dev>2024-11-13 22:45:57 -0600
committerParker <contact@pkrm.dev>2024-11-13 22:45:57 -0600
commitdbc53a555e64fdd0b848bf33b4208820b8701509 (patch)
tree9b89e5fc4a3fce4c68114010da6e3bb61b25d027
parent9ce608b637f3ade7346afbaf2bdd1dbf0a8767f7 (diff)
Update UI
-rw-r--r--app/src/components/Dashboard.tsx42
-rw-r--r--app/src/components/Login.tsx66
-rw-r--r--app/src/components/Navbar.tsx56
-rw-r--r--app/src/components/Signup.tsx84
-rw-r--r--app/src/styles/Auth.module.css (renamed from app/src/styles/Login.module.css)28
-rw-r--r--app/src/styles/Dashboard.module.css50
-rw-r--r--app/src/styles/Navbar.module.css19
7 files changed, 197 insertions, 148 deletions
diff --git a/app/src/components/Dashboard.tsx b/app/src/components/Dashboard.tsx
index e16c44e..f3442e0 100644
--- a/app/src/components/Dashboard.tsx
+++ b/app/src/components/Dashboard.tsx
@@ -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>
diff --git a/app/src/components/Login.tsx b/app/src/components/Login.tsx
index 807face..badb5b1 100644
--- a/app/src/components/Login.tsx
+++ b/app/src/components/Login.tsx
@@ -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>
</>
);
diff --git a/app/src/components/Navbar.tsx b/app/src/components/Navbar.tsx
index 5107bf4..53c1f52 100644
--- a/app/src/components/Navbar.tsx
+++ b/app/src/components/Navbar.tsx
@@ -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>
);
diff --git a/app/src/components/Signup.tsx b/app/src/components/Signup.tsx
index 5ec2e17..f4a3368 100644
--- a/app/src/components/Signup.tsx
+++ b/app/src/components/Signup.tsx
@@ -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>
</>
);
diff --git a/app/src/styles/Login.module.css b/app/src/styles/Auth.module.css
index b2bcddf..7e1d3e3 100644
--- a/app/src/styles/Login.module.css
+++ b/app/src/styles/Auth.module.css
@@ -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;
+}
+
+.errorHidden {
+ visibility: hidden;
color: #ee6161;
}
-.link {
+.footnoteLink {
text-decoration: underline;
color: #ccc;
-
}
-.link:hover {
+.footnoteLink:hover {
text-decoration: none;
color: #415eac;
}
-#bottomText {
+.footnote {
color: #606468;
-}
-
-.visible {
- visibility: visible;
-}
-
-.hidden {
- visibility: hidden;
} \ No newline at end of file
diff --git a/app/src/styles/Dashboard.module.css b/app/src/styles/Dashboard.module.css
index ef6b451..96ed919 100644
--- a/app/src/styles/Dashboard.module.css
+++ b/app/src/styles/Dashboard.module.css
@@ -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,40 +15,29 @@ 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;
}
-.linkTableRow td {
- padding: 20px;
+.mainTable {
+ position: absolute;
+ top: 100px;
+ left: 50%;
+ transform: translateX(-50%);
}
-.logTableRow table td {
- background-color: #3b4148;
- padding: 10px;
+.linkTableRow {
+ border: 2px solid #ccc;
}
-.logTableRow table tr {
- border: 2px solid #ccc;
+.linkTableRow td {
+ padding: 20px;
}
.linkButton {
@@ -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;
diff --git a/app/src/styles/Navbar.module.css b/app/src/styles/Navbar.module.css
index d8c3f72..09ad94c 100644
--- a/app/src/styles/Navbar.module.css
+++ b/app/src/styles/Navbar.module.css
@@ -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;
} \ No newline at end of file