Skip to content

Commit

Permalink
Merge pull request #137 from AndrewCS149/adminInsightsPage
Browse files Browse the repository at this point in the history
Add admin insights page
  • Loading branch information
The-DevBlog authored Sep 19, 2023
2 parents a94ddc2 + f77a005 commit d38ccf2
Show file tree
Hide file tree
Showing 10 changed files with 225 additions and 56 deletions.
4 changes: 3 additions & 1 deletion devblog/devblog/ClientApp/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ import Home from './pages/Home';
import SignIn from './pages/SignIn';
import Posts from './pages/Posts';
import SignUp from './pages/SignUp';
import "./global.css";
import About from './pages/About';
import Insights from './pages/Insights';
import "./global.css";

const App = () => {
return (
Expand All @@ -19,6 +20,7 @@ const App = () => {
<Route path="/posts" element={<Posts />} />
<Route path="/posts/create" element={<AddPost />} />
<Route path="/about" element={<About />} />
<Route path="/insights" element={<Insights />} />
<Route path="/signin" element={<SignIn />} />
<Route path="/signup" element={<SignUp />} />
<Route path="/signout" element={<SignOut />} />
Expand Down
34 changes: 19 additions & 15 deletions devblog/devblog/ClientApp/src/components/DeleteAccount.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,25 @@ const DeleteAccount = () => {
}, []);

const handleDelete = async () => {
await fetch(`api/accounts/${userName}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${localStorage.getItem("token")}`
}
}).then(async () => {
await fetch(`api/accounts/signout`, {
method: "POST",
headers: { "Content-Type": "application/json" },
}).then(() => {
localStorage.clear();
window.location.reload();
});
})
const shouldDelete = window.confirm("Are you sure?");

if (shouldDelete) {
await fetch(`api/accounts/${userName}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${localStorage.getItem("token")}`
}
}).then(async () => {
await fetch(`api/accounts/signout`, {
method: "POST",
headers: { "Content-Type": "application/json" },
}).then(() => {
localStorage.clear();
window.location.reload();
});
})
}
};

return <>{loggedIn && <button onClick={handleDelete} > Delete Account</button >}</>
Expand Down
7 changes: 7 additions & 0 deletions devblog/devblog/ClientApp/src/components/Nav.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,19 @@ import { Link, useLocation } from "react-router-dom";
import SignOut from "../pages/SignOut";
import { MdMenu } from "react-icons/md";
import { IsLoggedIn } from "../components/AuthenticationService";
import { GetIsAdmin } from "./AuthenticationService";
import "./styles/Nav.css";

const Nav = () => {
const [loggedIn, setLoggedIn] = useState(false);
const [userName, setUsername] = useState("");
const [isMenuClicked, setIsMenuClicked] = useState(false)
const [display, setDisplay] = useState("none")
const [isAdmin, setIsAdmin] = useState(false);
const location = useLocation();

useEffect(() => setIsAdmin(GetIsAdmin), []);

const isActive = (path: string) => {
return location.pathname === path ? "active" : "non-active";
};
Expand Down Expand Up @@ -52,6 +56,7 @@ const Nav = () => {
<Link to="/" className={isActive("/")}>Home</Link>
<Link to="/posts" className={isActive("/posts")}>Posts</Link>
<Link to="/about" className={isActive("/about")}>About</Link>
{isAdmin && <Link to="/insights" className={isActive("/insights")}>Insights</Link>}

{loggedIn ? (
<span className="accounts">
Expand All @@ -74,6 +79,8 @@ const Nav = () => {
<Link to="/" className={isActive("/")}>Home</Link>
<Link to="/posts" className={isActive("/posts")}>Posts</Link>
<Link to="/about" className={isActive("/about")}>About</Link>
{isAdmin && <Link to="/insights" className={isActive("/insights")}>Insights</Link>}

{loggedIn && <SignOut />}

{!loggedIn &&
Expand Down
13 changes: 10 additions & 3 deletions devblog/devblog/ClientApp/src/components/styles/Nav.css
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ s .navbar .nav-items a.active {

.nav-items>a:nth-child(1),
.nav-items>a:nth-child(2),
.nav-items>a:nth-child(3) {
.nav-items>a:nth-child(3),
.nav-items>a:nth-child(4) {
margin-top: auto;
margin-bottom: 5px;
}
Expand Down Expand Up @@ -96,7 +97,10 @@ s .navbar .nav-items a.active {
.mobile-nav-links form {
text-decoration: none;
padding-top: 5px;
/* border: 2px solid yellow; */
}

.mobile-nav-links>a:hover {
opacity: 1.0;
}

.mobile-nav-links a.active {
Expand All @@ -120,9 +124,12 @@ s .navbar .nav-items a.active {
flex-direction: column;
}

.logout-form {
width: fit-content;
}

.logout {
font-size: 16px;
margin-left: auto;
padding: 0px;
}
}
36 changes: 19 additions & 17 deletions devblog/devblog/ClientApp/src/pages/AddPost.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,26 +113,28 @@ const AddPost = () => {
</div>
</div>

<label>Image
<input
type="file"
required
multiple
onChange={(e) => e.target.files && setFile(Array.from(e.target.files))} />
</label>
<div className="new-post-info">
<label>Image
<input
type="file"
required
multiple
onChange={(e) => e.target.files && setFile(Array.from(e.target.files))} />
</label>

<label>Description
<p>Mastodon char count: {charCount}/500</p>
<div className="addpost-description">
<textarea onChange={(e) => setDescription(e.currentTarget.value)} />
</div>
</label>
<label>Description
<p>Mastodon character limit: {charCount}/500</p>
<div className="addpost-description">
<textarea placeholder="Write description here..." onChange={(e) => setDescription(e.currentTarget.value)} />
</div>
</label>

<p>Preview:</p>
<div className="post-preview">
<ReactMarkdown children={description} />
<p>Preview:</p>
<div className="post-preview">
<ReactMarkdown children={description} />
</div>
<button>Create Post</button>
</div>
<button>Create Post</button>
</form>
}
</div >
Expand Down
71 changes: 71 additions & 0 deletions devblog/devblog/ClientApp/src/pages/Insights.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import { useEffect, useState } from "react";
import "./styles/Insights.css";
import { MdDelete as Trash } from "react-icons/md";

interface IUserInfo {
userName: string,
email: string
}

const Insights = () => {
const [users, setUsers] = useState<IUserInfo[]>();

const getUsers = async () => {
await fetch("api/accounts/count", {
method: "GET",
headers: {
"Authorization": `Bearer ${localStorage.getItem("token")}`
}
}).then((res) => { return res.json(); })
.then((data) => {
setUsers(data);
});
}

const handleDeleteAccount = async (userName: string) => {
const shouldDelete = window.confirm(`Are you sure you would like to delete user ${userName}?`);

if (shouldDelete) {
await fetch(`api/accounts/admin/${userName}`, {
method: "DELETE",
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${localStorage.getItem("token")}`
}
}).then(() => {
// users.filter((user) => user.userName !== userNameToRemove);
setUsers(users?.filter((user) => user.userName !== userName));
})
.catch((e) => console.log(`Error deleting account: ${e}`));
}
}

useEffect(() => { getUsers() }, []);

return (
<section className="insights">
<p>Total Users: {users?.length}</p>

<table className="user-table">
<thead>
<tr>
<th>Username</th>
<th>Email</th>
<th>Delete</th>
</tr>
</thead>
<tbody>
{users?.map((user, index) => (
<tr key={index}>
<td>{user.userName}</td>
<td>{user.email}</td>
<td><Trash className="delete-post-btn" onClick={() => handleDeleteAccount(user.userName)} /></td>
</tr>
))}
</tbody>
</table>
</section>
)
}

export default Insights;
2 changes: 1 addition & 1 deletion devblog/devblog/ClientApp/src/pages/SignOut.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ const SignOut = () => {
};

return (
<form onSubmit={handleSignOut}>
<form className="logout-form" onSubmit={handleSignOut}>
<button className="logout">Logout</button>
</form>
);
Expand Down
42 changes: 26 additions & 16 deletions devblog/devblog/ClientApp/src/pages/styles/AddPost.css
Original file line number Diff line number Diff line change
@@ -1,3 +1,20 @@
.upload-platforms {
background-color: rgb(26, 32, 41);
border: .15em solid rgb(70, 68, 60);
border-radius: .5em;
margin-bottom: 40px;
padding: 10px 20px;
}

.upload-status>h4 p {
color: red;
margin-left: 30px;
}

.upload-platforms ul {
list-style: none;
}

.create-post {
align-items: center;
justify-content: center;
Expand All @@ -23,41 +40,34 @@ a {
color: white;
}

.new-post-info {
background-color: rgb(26, 32, 41);
border: .15em solid rgb(70, 68, 60);
border-radius: .5em;
padding: 10px 20px;
}

.addpost-description {
display: flex;
}

.addpost-description>textarea {
background-color: rgb(26, 32, 41);
/* background-color: rgb(26, 32, 41); */
width: 100%;
min-height: 100px;
resize: none;
outline: none;
font-size: 17;
border: none;
border-right: 2px solid rgb(70, 68, 60);
}

.post-preview {
padding: 20px;
margin-bottom: 20px;
min-height: 100px;
background-color: rgb(26, 32, 41);
/* background-color: rgb(26, 32, 41); */
}

.create-post {
font-family: 'Chivo Mono', monospace;
}

.upload-platforms {
margin-bottom: 40px;
}

.upload-status>h4 p {
color: red;
margin-left: 30px;
}

.upload-platforms ul {
list-style: none;
}
21 changes: 21 additions & 0 deletions devblog/devblog/ClientApp/src/pages/styles/Insights.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.insights {
font-family: 'Chivo Mono', monospace;
margin-top: 150px;
}

.insights>table {
border: .15em solid rgb(70, 68, 60);
border-radius: .5em;
width: 100%;
}


.insights>table th,
.insights>table td {
padding: 15px;
text-align: left;
}

.insights>table>tbody tr:nth-child(odd) {
background-color: rgb(26, 32, 41);
}
Loading

0 comments on commit d38ccf2

Please sign in to comment.