implement new admin dashboard

This commit is contained in:
Aidan 2024-12-31 01:41:07 -05:00
parent df86fa5f3f
commit a110f4450d
No known key found for this signature in database
GPG Key ID: 1773A01F0EFE4FC1
6 changed files with 177 additions and 48 deletions

17
app.js
View File

@ -158,7 +158,7 @@ app.post('/admin', (req, res) => {
app.get('/admin/dashboard', checkAdminAuth, async (req, res) => {
const requests = await Request.findAll();
res.render('admin/dash', { requests, currentPage: 'admin' });
res.render('admin/dash', { requests, currentPage: 'admin', user: process.env.ADMIN_USERNAME });
});
app.post('/admin/update-status', checkAdminAuth, async (req, res) => {
@ -173,6 +173,21 @@ app.post('/admin/delete-request', checkAdminAuth, async (req, res) => {
res.redirect('/admin/dashboard');
});
app.get('/admin/edit/:id', checkAdminAuth, async (req, res) => {
const { id } = req.params;
const request = await Request.findByPk(id);
if (!request) {
return res.status(404).render('error/404');
}
res.render('admin/edit', { request, currentPage: 'admin' });
});
app.post('/admin/edit', checkAdminAuth, async (req, res) => {
const { id, fullName, email, reason, telegram } = req.body;
await Request.update({ fullName, email, reason, telegram }, { where: { id } });
res.redirect('/admin/dashboard');
});
// Start server on internal port defined in .env
app.listen(process.env.INTERNAL_PORT, () => {
console.log(`Server started on port ${process.env.INTERNAL_PORT}`);

40
public/js/admin.js Normal file
View File

@ -0,0 +1,40 @@
const body = document.body;
const modeSwitch = document.getElementById('modeSwitch');
const iconSwitch = document.getElementById('iconSwitch');
const nav = document.getElementById('nav');
function getCookie(name) {
const match = document.cookie.match(new RegExp('(^| )' + name + '=([^;]+)'));
return match ? match[2] : null;
}
function setCookie(name, value, days) {
const d = new Date();
d.setTime(d.getTime() + (days * 24 * 60 * 60 * 1000));
document.cookie = `${name}=${value}; expires=${d.toUTCString()}; path=/`;
}
function toggleTheme(theme) {
const isDark = theme === 'dark';
body.classList.toggle('dark-mode', isDark);
body.classList.toggle('light-mode', !isDark);
iconSwitch.classList.toggle('bi-moon', isDark);
iconSwitch.classList.toggle('text-white', isDark);
iconSwitch.classList.toggle('bi-brightness-high', !isDark);
iconSwitch.classList.toggle('text-black', !isDark);
nav.classList.toggle('navbar-dark', isDark);
nav.classList.toggle('bg-dark', isDark);
nav.classList.toggle('navbar-light', !isDark);
nav.classList.toggle('bg-light', !isDark);
}
document.addEventListener('DOMContentLoaded', () => {
const theme = getCookie('theme') || 'light';
toggleTheme(theme);
});
modeSwitch.addEventListener('click', () => {
const newTheme = body.classList.contains('dark-mode') ? 'light' : 'dark';
setCookie('theme', newTheme, 30);
toggleTheme(newTheme);
});

View File

@ -1,10 +1,12 @@
<%- include('../shards/header', { title: 'Admin Dashboard - p0ntus mail' }) %>
<div class="lg-container">
<%- include('../shards/nav', { currentPage: 'admin' }) %>
<i class="il mt-5">Dashboard</i>
<hr>
<table class="table">
<thead>
<%- include('shards/header', { title: 'Admin Dashboard - p0ntus mail' }) %>
<div class="container my-5">
<div class="text-center mb-4">
<h1 class="fw-bold">Welcome, <%= user %>!</h1>
<p>You are at viewing <b>all requests</b></p>
</div>
<div class="table-responsive">
<table class="table align-middle table-hover">
<thead class="table-dark">
<tr>
<th>ID</th>
<th>Full Name</th>
@ -26,25 +28,31 @@
<td><%= request.telegram %></td>
<td><%= request.status %></td>
<td>
<form action="/admin/update-status" method="POST">
<form action="/admin/update-status" method="POST" class="d-inline">
<input type="hidden" name="id" value="<%= request.id %>">
<select name="status" class="form-control">
<select name="status" class="form-select form-select-sm">
<option value="Pending" <% if (request.status === 'Pending') { %>selected<% } %>>Pending</option>
<option value="Approved" <% if (request.status === 'Approved') { %>selected<% } %>>Approved</option>
<option value="Denied" <% if (request.status === 'Denied') { %>selected<% } %>>Denied</option>
</select>
<button type="submit" class="btn btn-primary mt-2">Update</button>
<button type="submit" class="btn btn-primary btn-sm mt-2">Update</button>
</form>
</td>
<td>
<form action="/admin/delete-request" method="POST">
<a href="/admin/edit/<%= request.id %>" class="btn btn-warning btn-sm">
<i class="bi bi-pencil"></i>
</a>
<form action="/admin/delete-request" method="POST" class="d-inline">
<input type="hidden" name="id" value="<%= request.id %>">
<button type="submit" class="btn btn-danger mt-2">Delete</button>
<button type="submit" class="btn btn-danger btn-sm">
<i class="bi bi-trash3"></i>
</button>
</form>
</td>
</tr>
<% }); %>
</tbody>
</table>
</div>
</div>
<%- include('../shards/footer') %>
<%- include('shards/footer') %>

25
src/admin/edit.ejs Normal file
View File

@ -0,0 +1,25 @@
<%- include('shards/header', { title: 'Edit Request - p0ntus mail' }) %>
<div class="container my-5">
<h2 class="mb-4">Edit Request</h2>
<form action="/admin/edit" method="POST">
<input type="hidden" name="id" value="<%= request.id %>">
<div class="mb-3">
<label for="fullName" class="form-label">Full Name</label>
<input type="text" class="form-control" id="fullName" name="fullName" value="<%= request.fullName %>" required>
</div>
<div class="mb-3">
<label for="email" class="form-label">Email</label>
<input type="text" class="form-control" id="email" name="email" value="<%= request.email %>" required>
</div>
<div class="mb-3">
<label for="reason" class="form-label">Reason</label>
<textarea class="form-control" id="reason" name="reason" rows="3"><%= request.reason %></textarea>
</div>
<div class="mb-3">
<label for="telegram" class="form-label">Telegram</label>
<input type="text" class="form-control" id="telegram" name="telegram" value="<%= request.telegram %>">
</div>
<button type="submit" class="btn btn-primary">Update</button>
</form>
</div>
<%- include('shards/footer') %>

View File

@ -0,0 +1,4 @@
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js" integrity="sha384-YvpcrYf0tY3lHB60NNkmXc5s9fDVZLESaAA55NDzOxhy9GkcIdslK1eN7N6jIeHz" crossorigin="anonymous"></script>
<script src="/js/admin.js"></script>
</body>
</html>

View File

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title><%= title %></title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-icons/1.11.3/font/bootstrap-icons.min.css" integrity="sha512-dPXYcDub/aeb08c63jRq/k6GaKccl256JQy/AnOq7CAnEZ9FzSL9wSbcZkMp4R26vBsMLFYH4kQ67/bbV8XaCQ==" crossorigin="anonymous" referrerpolicy="no-referrer" />
<style>
:root {
--bg-color-light: #f9f9f9;
--text-color-light: #333;
--bg-color-dark: #1c1c1c;
--text-color-dark: #fff;
}
body.light-mode {
background-color: var(--bg-color-light);
color: var(--text-color-light);
}
body.dark-mode {
background-color: var(--bg-color-dark);
color: var(--text-color-dark);
}
.mode-switch {
cursor: pointer;
margin-left: 1rem;
}
</style>
</head>
<body class="light-mode">
<nav id="nav" class="navbar navbar-expand-lg navbar-light bg-light px-4">
<a class="navbar-brand" href="#">p0ntus Mail Admin</a>
<div class="ms-auto">
<span class="mode-switch" id="modeSwitch">
<i id="iconSwitch" class="bi-moon text-black"></i>
</span>
</div>
</nav>