implement new admin dashboard
This commit is contained in:
parent
df86fa5f3f
commit
a110f4450d
17
app.js
17
app.js
@ -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
40
public/js/admin.js
Normal 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);
|
||||
});
|
@ -1,50 +1,58 @@
|
||||
<%- 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>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Full Name</th>
|
||||
<th>Email</th>
|
||||
<th>Reason</th>
|
||||
<th>Telegram</th>
|
||||
<th>Status</th>
|
||||
<th>Update Status</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% requests.forEach(request => { %>
|
||||
<%- 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>
|
||||
<td><%= request.id %></td>
|
||||
<td><%= request.fullName %></td>
|
||||
<td><%= request.email %></td>
|
||||
<td><%= request.reason %></td>
|
||||
<td><%= request.telegram %></td>
|
||||
<td><%= request.status %></td>
|
||||
<td>
|
||||
<form action="/admin/update-status" method="POST">
|
||||
<input type="hidden" name="id" value="<%= request.id %>">
|
||||
<select name="status" class="form-control">
|
||||
<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>
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
<form action="/admin/delete-request" method="POST">
|
||||
<input type="hidden" name="id" value="<%= request.id %>">
|
||||
<button type="submit" class="btn btn-danger mt-2">Delete</button>
|
||||
</form>
|
||||
</td>
|
||||
<th>ID</th>
|
||||
<th>Full Name</th>
|
||||
<th>Email</th>
|
||||
<th>Reason</th>
|
||||
<th>Telegram</th>
|
||||
<th>Status</th>
|
||||
<th>Update Status</th>
|
||||
<th>Delete</th>
|
||||
</tr>
|
||||
<% }); %>
|
||||
</tbody>
|
||||
</table>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% requests.forEach(request => { %>
|
||||
<tr>
|
||||
<td><%= request.id %></td>
|
||||
<td><%= request.fullName %></td>
|
||||
<td><%= request.email %></td>
|
||||
<td><%= request.reason %></td>
|
||||
<td><%= request.telegram %></td>
|
||||
<td><%= request.status %></td>
|
||||
<td>
|
||||
<form action="/admin/update-status" method="POST" class="d-inline">
|
||||
<input type="hidden" name="id" value="<%= request.id %>">
|
||||
<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 btn-sm mt-2">Update</button>
|
||||
</form>
|
||||
</td>
|
||||
<td>
|
||||
<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 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
25
src/admin/edit.ejs
Normal 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') %>
|
4
src/admin/shards/footer.ejs
Normal file
4
src/admin/shards/footer.ejs
Normal 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>
|
37
src/admin/shards/header.ejs
Normal file
37
src/admin/shards/header.ejs
Normal 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>
|
Reference in New Issue
Block a user