aboutsummaryrefslogtreecommitdiff
path: root/app
diff options
context:
space:
mode:
Diffstat (limited to 'app')
-rw-r--r--app/package.json3
-rw-r--r--app/src/App.tsx1
-rw-r--r--app/src/components/Dashboard.tsx142
-rw-r--r--app/src/styles/Dashboard.module.css33
-rw-r--r--app/yarn.lock47
5 files changed, 179 insertions, 47 deletions
diff --git a/app/package.json b/app/package.json
index 0ad2c45..4ba8808 100644
--- a/app/package.json
+++ b/app/package.json
@@ -10,6 +10,9 @@
"preview": "vite preview"
},
"dependencies": {
+ "@fortawesome/fontawesome-svg-core": "^6.6.0",
+ "@fortawesome/free-solid-svg-icons": "^6.6.0",
+ "@fortawesome/react-fontawesome": "^0.2.2",
"axios": "^1.7.7",
"react": "^18.3.1",
"react-dom": "^18.3.1",
diff --git a/app/src/App.tsx b/app/src/App.tsx
index 75cd203..14fa571 100644
--- a/app/src/App.tsx
+++ b/app/src/App.tsx
@@ -1,5 +1,4 @@
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
-// Import components
import Login from './components/Login'
import Signup from './components/Signup'
import Dashboard from './components/Dashboard'
diff --git a/app/src/components/Dashboard.tsx b/app/src/components/Dashboard.tsx
index bcab092..373a07f 100644
--- a/app/src/components/Dashboard.tsx
+++ b/app/src/components/Dashboard.tsx
@@ -1,46 +1,126 @@
-import { useState, useEffect } from 'react';
+import React, { useState, useEffect } from 'react';
import Axios from 'axios';
import styles from '../styles/Dashboard.module.css';
-// import { accessAPI } from '../helpers/api';
-
+import { useNavigate } from 'react-router-dom';
+import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
+import { faTrash } from '@fortawesome/free-solid-svg-icons';
function Dashboard() {
- // Get the links from the API
- const [links, setLinks] = useState([]);
+ interface Log {
+ id: number;
+ link: string;
+ timestamp: string;
+ ip: string;
+ location: string;
+ browser: string;
+ os: string;
+ userAgent: string;
+ isp: string;
+ }
+
+ interface Link {
+ link: string;
+ owner: number;
+ redirect_link: string;
+ expire_date: string;
+ }
+
+ const [links, setLinks] = useState<Link[]>([]);
+ const [logs, setLogs] = useState<Log[]>([]);
+ const [visibleLog, setVisibleLog] = useState<string | null>(null);
+ const navigate = useNavigate();
+
+ // Fetch links from API
useEffect(() => {
- Axios.get('/api/links')
- .then((res) => {
+ Axios.get('/api/links').then((res) => {
+ if (res.status === 200) {
setLinks(res.data);
- })
- .catch((err) => {
- console.log(err);
- });
+ } else {
+ navigate('/login');
+ }
+ }).catch(() => {
+ navigate('/login');
+ });
+ }, []);
+
+ // Fetch logs from API
+ useEffect(() => {
+ Axios.get('/api/logs').then((res) => {
+ if (res.status === 200) {
+ setLogs(res.data);
+ } else {
+ navigate('/login');
+ }
+ }).catch(() => {
+ navigate('/login');
+ });
}, []);
+ const toggleLogRow = (link: string) => {
+ setVisibleLog(visibleLog === link ? null : link);
+ };
+
return (
- <div id={styles.container}>
- <table>
- <thead>
- <tr style={{ border: '2px solid #ccc' }}>
- <th>Link</th>
- <th>Visits</th>
- <th>Redirect</th>
- <th>Expire Date</th>
- </tr>
- </thead>
- <tbody>
- {/* {links.map((link: any) => (
- <tr key={link.id}>
- <td>{link.url}</td>
- <td>{link.visits}</td>
- <td>{link.redirect}</td>
+ <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>
- ))} */}
- </tbody>
- </table>
- </div>
+
+ {/* 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}/></td>
+ </tr>
+ ))}
+ </tbody>
+ </table>
+ </td>
+ </tr>
+ )}
+ </React.Fragment>
+ ))}
+ </tbody>
+ </table>
)
}
diff --git a/app/src/styles/Dashboard.module.css b/app/src/styles/Dashboard.module.css
index 042a2f1..ef6b451 100644
--- a/app/src/styles/Dashboard.module.css
+++ b/app/src/styles/Dashboard.module.css
@@ -5,15 +5,15 @@ body {
background-color: #2c3338;
}
-#container {
- display: flex;
- justify-content: center;
- margin-top: 100px;
+#mainTable {
+ position: absolute;
+ top: 100px;
+ left: 50%;
+ transform: translateX(-50%);
}
-
table {
- margin: 20px 0 20px 0;
+ margin: 0 auto;
text-align: center;
font-size: 25px;
width: 1000px;
@@ -23,11 +23,11 @@ table {
}
/* Center all sub tables */
-.log-table-row table {
+.logTableRow table {
margin: 0 auto;
}
-.log-table-row table {
+.logTableRow table {
width: 90%;
}
@@ -37,7 +37,7 @@ table th {
padding: 10px;
}
-.link-table-row {
+.linkTableRow {
border: 2px solid #ccc;
}
@@ -45,20 +45,20 @@ table td {
padding: 10px;
}
-.link-table-row td {
+.linkTableRow td {
padding: 20px;
}
-.log-table-row table td {
+.logTableRow table td {
background-color: #3b4148;
padding: 10px;
}
-.log-table-row table tr {
+.logTableRow table tr {
border: 2px solid #ccc;
}
-.link-button {
+.linkButton {
background-color: #3b4148;
color: #ccc;
border: none;
@@ -68,7 +68,12 @@ table td {
border-radius: 5px;
}
-.fa-trash:hover {
+.trashBin:hover {
color: rgb(238, 86, 86);
cursor: pointer;
+ transition: color 0.2s ease;
+}
+
+.trashBin:active {
+ transform: scale(0.95);
} \ No newline at end of file
diff --git a/app/yarn.lock b/app/yarn.lock
index 23ce4d2..189fe6d 100644
--- a/app/yarn.lock
+++ b/app/yarn.lock
@@ -336,6 +336,32 @@
dependencies:
levn "^0.4.1"
+"@fortawesome/fontawesome-common-types@6.6.0":
+ version "6.6.0"
+ resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz#31ab07ca6a06358c5de4d295d4711b675006163f"
+ integrity sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==
+
+"@fortawesome/fontawesome-svg-core@^6.6.0":
+ version "6.6.0"
+ resolved "https://registry.yarnpkg.com/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz#2a24c32ef92136e98eae2ff334a27145188295ff"
+ integrity sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==
+ dependencies:
+ "@fortawesome/fontawesome-common-types" "6.6.0"
+
+"@fortawesome/free-solid-svg-icons@^6.6.0":
+ version "6.6.0"
+ resolved "https://registry.yarnpkg.com/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz#061751ca43be4c4d814f0adbda8f006164ec9f3b"
+ integrity sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==
+ dependencies:
+ "@fortawesome/fontawesome-common-types" "6.6.0"
+
+"@fortawesome/react-fontawesome@^0.2.2":
+ version "0.2.2"
+ resolved "https://registry.yarnpkg.com/@fortawesome/react-fontawesome/-/react-fontawesome-0.2.2.tgz#68b058f9132b46c8599875f6a636dad231af78d4"
+ integrity sha512-EnkrprPNqI6SXJl//m29hpaNzOp1bruISWaOiRtkMi/xSvHJlzc2j2JAYS7egxt/EbjSNV/k6Xy0AQI6vB2+1g==
+ dependencies:
+ prop-types "^15.8.1"
+
"@humanfs/core@^0.19.1":
version "0.19.1"
resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77"
@@ -1209,7 +1235,7 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
-loose-envify@^1.1.0:
+loose-envify@^1.1.0, loose-envify@^1.4.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
@@ -1282,6 +1308,11 @@ node-releases@^2.0.18:
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.18.tgz#f010e8d35e2fe8d6b2944f03f70213ecedc4ca3f"
integrity sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==
+object-assign@^4.1.1:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+ integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==
+
optionator@^0.9.3:
version "0.9.4"
resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.9.4.tgz#7ea1c1a5d91d764fb282139c88fe11e182a3a734"
@@ -1349,6 +1380,15 @@ prelude-ls@^1.2.1:
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.2.1.tgz#debc6489d7a6e6b0e7611888cec880337d316396"
integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==
+prop-types@^15.8.1:
+ version "15.8.1"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5"
+ integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==
+ dependencies:
+ loose-envify "^1.4.0"
+ object-assign "^4.1.1"
+ react-is "^16.13.1"
+
proxy-from-env@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2"
@@ -1372,6 +1412,11 @@ react-dom@^18.3.1:
loose-envify "^1.1.0"
scheduler "^0.23.2"
+react-is@^16.13.1:
+ version "16.13.1"
+ resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
+ integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
+
react-refresh@^0.14.2:
version "0.14.2"
resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.14.2.tgz#3833da01ce32da470f1f936b9d477da5c7028bf9"