Nest intial code
This commit is contained in:
commit
7b299ae5b5
8 changed files with 2217 additions and 0 deletions
251
views/admin.ejs
Normal file
251
views/admin.ejs
Normal file
|
@ -0,0 +1,251 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.5/dist/css/bootstrap.min.css"
|
||||
/>
|
||||
<!-- Bootstrap JS Bundle (includes Popper) -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<title>SaifURL Admin</title>
|
||||
</head>
|
||||
<body class="bg-light">
|
||||
<div class="container py-5">
|
||||
<h1 class="text-center mb-4 fw-bold text-primary">Saif URLs</h1>
|
||||
|
||||
<!-- Token input and New URL Button -->
|
||||
<form
|
||||
action="/shorturls"
|
||||
method="POST"
|
||||
class="my-4 p-5 bg-white shadow-lg rounded"
|
||||
>
|
||||
<h2 class="text-center mb-4 fw-bold text-secondary">
|
||||
Create a Short URL
|
||||
</h2>
|
||||
<div class="row g-4">
|
||||
<!-- Full URL -->
|
||||
<div class="col-md-6">
|
||||
<label for="fullUrl" class="form-label fw-bold">Full URL</label>
|
||||
<input
|
||||
required
|
||||
placeholder="Enter the full URL"
|
||||
type="url"
|
||||
name="fullUrl"
|
||||
id="fullUrl"
|
||||
class="form-control border-secondary"
|
||||
/>
|
||||
</div>
|
||||
<input
|
||||
type="hidden"
|
||||
name="token"
|
||||
id="tokeninput"
|
||||
value="<%= token %>"
|
||||
/>
|
||||
<!-- Custom Short URL -->
|
||||
<div class="col-md-4">
|
||||
<label for="customShortUrl" class="form-label fw-bold"
|
||||
>Custom Short URL
|
||||
</label>
|
||||
<input
|
||||
type="text"
|
||||
name="customShortUrl"
|
||||
id="customShortUrl"
|
||||
placeholder="Enter custom short URL (optional)"
|
||||
class="form-control border-secondary"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<!-- Submit Button -->
|
||||
<div class="col-md-2 d-flex align-items-end">
|
||||
<button class="btn btn-success w-100 fw-bold" type="submit">
|
||||
Shorten
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="table-responsive shadow-sm rounded bg-white p-4">
|
||||
<table class="table table-striped table-hover align-middle">
|
||||
<thead class="table-dark">
|
||||
<tr>
|
||||
<th>Full URL</th>
|
||||
<th>Short</th>
|
||||
<th>Clicks</th>
|
||||
<th>Options</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<% shortUrls.forEach(shortUrl => { %>
|
||||
<tr>
|
||||
<td>
|
||||
<a
|
||||
href="<%= shortUrl.full %>"
|
||||
target="_blank"
|
||||
class="text-decoration-none text-primary fw-bold"
|
||||
><%= shortUrl.full %></a
|
||||
>
|
||||
</td>
|
||||
<td>
|
||||
<a
|
||||
href="<%= shortUrl.short %>"
|
||||
target="_blank"
|
||||
class="text-decoration-none text-success fw-bold"
|
||||
><%= shortUrl.short %></a
|
||||
>
|
||||
</td>
|
||||
<td class="text-center fw-bold"><%= shortUrl.clicks %></td>
|
||||
<td>
|
||||
<!-- Edit Button -->
|
||||
<button
|
||||
class="btn btn-warning btn-sm me-2 fw-bold"
|
||||
data-bs-toggle="modal"
|
||||
data-bs-target="#editModal<%= shortUrl._id %>"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
|
||||
<!-- Delete Button -->
|
||||
<button
|
||||
onclick="deleteUrl('<%= shortUrl._id %>')"
|
||||
class="btn btn-danger btn-sm"
|
||||
>
|
||||
Delete
|
||||
</button>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<!-- Edit Modal -->
|
||||
<div
|
||||
class="modal fade"
|
||||
id="editModal<%= shortUrl._id %>"
|
||||
tabindex="-1"
|
||||
aria-labelledby="editModalLabel<%= shortUrl._id %>"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<div class="modal-dialog">
|
||||
<div class="modal-content">
|
||||
<form id="editForm<%= shortUrl._id %>">
|
||||
<div class="modal-header">
|
||||
<h5
|
||||
class="modal-title"
|
||||
id="editModalLabel<%= shortUrl._id %>"
|
||||
>
|
||||
Edit URL
|
||||
</h5>
|
||||
<button
|
||||
type="button"
|
||||
class="btn-close"
|
||||
data-bs-dismiss="modal"
|
||||
aria-label="Close"
|
||||
></button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="mb-3">
|
||||
<label
|
||||
for="fullUrl<%= shortUrl._id %>"
|
||||
class="form-label"
|
||||
>Full URL</label
|
||||
>
|
||||
<input
|
||||
type="url"
|
||||
class="form-control"
|
||||
id="fullUrl<%= shortUrl._id %>"
|
||||
name="fullUrl"
|
||||
value="<%= shortUrl.full %>"
|
||||
required
|
||||
/>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label
|
||||
for="customShortUrl<%= shortUrl._id %>"
|
||||
class="form-label"
|
||||
>Custom Short URL</label
|
||||
>
|
||||
<input
|
||||
type="text"
|
||||
class="form-control"
|
||||
id="customShortUrl<%= shortUrl._id %>"
|
||||
name="customShortUrl"
|
||||
value="<%= shortUrl.short %>"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button
|
||||
type="button"
|
||||
class="btn btn-secondary"
|
||||
data-bs-dismiss="modal"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
<button type="submit" class="btn btn-primary">
|
||||
Save Changes
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const form = document.getElementById("editForm<%= shortUrl._id %>");
|
||||
const fullUrlInput = document.getElementById("fullUrl<%= shortUrl._id %>");
|
||||
const customShortUrlInput = document.getElementById("customShortUrl<%= shortUrl._id %>");
|
||||
const token = "<%= token %>";
|
||||
const url = `/shorturls/<%= shortUrl._id %>?token=${token}`;
|
||||
|
||||
if (form) {
|
||||
form.addEventListener("submit", async (e) => {
|
||||
e.preventDefault();
|
||||
|
||||
const fullUrl = fullUrlInput.value;
|
||||
const customShortUrl = customShortUrlInput.value;
|
||||
|
||||
try {
|
||||
const response = await fetch(url, {
|
||||
method: "PATCH",
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ fullUrl, customShortUrl }),
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(data.message || "Server error while updating.");
|
||||
}
|
||||
|
||||
if (data.success) {
|
||||
window.location.reload();
|
||||
} else {
|
||||
alert("Failed to update URL: " + (data.message || "Unknown error"));
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Update error:", error);
|
||||
alert("Something went wrong while updating the URL.");
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
</script>
|
||||
|
||||
<% }) %>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
async function deleteUrl(id) {
|
||||
const token = new URLSearchParams(window.location.search).get("token");
|
||||
if (!confirm("Delete this URL?")) return;
|
||||
await fetch(`/shorturls/${id}?token=${token}`, { method: "DELETE" });
|
||||
window.location.reload(); // Reload after deletion
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
Loading…
Add table
Add a link
Reference in a new issue