sub deletion

This commit is contained in:
Corban-Lee Jones 2025-02-11 21:54:40 +00:00
parent a146a4793c
commit 08a286db13
4 changed files with 76 additions and 45 deletions

View File

@ -17,6 +17,30 @@ const formatTimestamp = timestamp => {
: `${d.getDate()} ${d.toLocaleString("en-GB", { month: "short" })} ${d.getFullYear()}`;
}
const emptyTableHtml = `
<div class="max-w-md w-full min-h-[400px] flex flex-col justify-center mx-auto px-6 py-4">
<div class="flex justify-center items-center size-[46px] bg-gray-100 rounded-lg dark:bg-neutral-800">
<svg class="shrink-0 size-6 text-gray-600 dark:text-neutral-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11a9 9 0 0 1 9 9"></path><path d="M4 4a16 16 0 0 1 16 16"></path><circle cx="5" cy="19" r="1"></circle></svg>
</div>
<h2 class="mt-5 font-semibold text-gray-800 dark:text-white">
No results found
</h2>
<p class="mt-2 text-sm text-gray-600 dark:text-neutral-400">
Create a subscription and it will appear here.
</p>
<div class="mt-5 flex flex-col sm:flex-row gap-2">
<button type="button" class="openSubModal-js py-2 px-3 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none" data-hs-overlay="#subModal">
<svg class="shrink-0 size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
Create a subscription
</button>
<button type="button" onclick="alert('not implemented');" class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-gray-200 bg-white text-gray-800 shadow-sm hover:bg-gray-50 focus:outline-none focus:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700">
Use a Template
</button>
</div>
</div>
`;
var table;
const defineTable = () => {
table = new HSDataTable("#table", {
@ -24,8 +48,9 @@ const defineTable = () => {
url: `/guild/${guildId}/subscriptions/api/datatable`,
dataSrc: "data",
data: (d) => {
d.filters = {};
if (d === undefined) { return ;}
d.filters = {};
const active = $("input[name='filterActive']:checked").val();
d.filters.active = active;
}
@ -40,32 +65,12 @@ const defineTable = () => {
selectAllSelector: "#selectAllBox"
},
language: {
zeroRecords: `
<div class="max-w-md w-full min-h-[400px] flex flex-col justify-center mx-auto px-6 py-4">
<div class="flex justify-center items-center size-[46px] bg-gray-100 rounded-lg dark:bg-neutral-800">
<svg class="shrink-0 size-6 text-gray-600 dark:text-neutral-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" width="24" height="24" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><path d="M4 11a9 9 0 0 1 9 9"></path><path d="M4 4a16 16 0 0 1 16 16"></path><circle cx="5" cy="19" r="1"></circle></svg>
</div>
<h2 class="mt-5 font-semibold text-gray-800 dark:text-white">
No results found
</h2>
<p class="mt-2 text-sm text-gray-600 dark:text-neutral-400">
Create a subscription and it will appear here.
</p>
<div class="mt-5 flex flex-col sm:flex-row gap-2">
<button type="button" class="openSubModal-js py-2 px-3 inline-flex justify-center items-center gap-x-2 text-sm font-medium rounded-lg border border-transparent bg-blue-600 text-white hover:bg-blue-700 focus:outline-none focus:bg-blue-700 disabled:opacity-50 disabled:pointer-events-none" data-hs-overlay="#subModal">
<svg class="shrink-0 size-4" xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12h14"/><path d="M12 5v14"/></svg>
Create a subscription
</button>
<button type="button" onclick="alert('not implemented');" class="py-2 px-3 inline-flex items-center gap-x-2 text-sm font-medium rounded-lg border border-gray-200 bg-white text-gray-800 shadow-sm hover:bg-gray-50 focus:outline-none focus:bg-gray-50 disabled:opacity-50 disabled:pointer-events-none dark:bg-neutral-800 dark:border-neutral-700 dark:text-white dark:hover:bg-neutral-700 dark:focus:bg-neutral-700">
Use a Template
</button>
</div>
</div>
`
zeroRecords: emptyTableHtml,
emptyTable: emptyTableHtml,
loading: "Placeholder Loading Message...",
},
rowCallback: (row, data, index) => {
$(row).addClass("bg-white hover:bg-gray-50 dark:bg-neutral-900 dark:hover:bg-neutral-800");
$(row).addClass("bg-white hover:bg-gray-50 dark:bg-neutral-800 dark:hover:bg-neutral-700");
},
drawCallback: () => {
HSDropdown.autoInit();
@ -248,7 +253,10 @@ const defineTable = () => {
]
})
table.dataTable.on("select", onTableSelectChange).on("deselect", onTableSelectChange);
table.dataTable
.on("select", onTableSelectChange)
.on("deselect", onTableSelectChange)
.on("draw", onTableSelectChange);
}
// Ensure the datatable recognises when all rows are selected, otherwise rows are only visually selected
@ -265,6 +273,24 @@ const onTableSelectChange = () => {
selectedRowCount === 0 ? $elem.hide() : $elem.show();
}
$("#deleteRowsBtn").on("click", async () => {
const rowIds = table.dataTable.rows({ selected: true }).data().toArray().map(row => row.id);
console.log(JSON.stringify(rowIds))
await $.ajax({
url: `/guild/${guildId}/subscriptions/api`,
method: "delete",
dataType: "json",
data: { ids: rowIds },
success: () => {
table.dataTable.draw();
table.dataTable.rows().deselect();
},
error: error => {
alert(typeof error === "object" ? JSON.stringify(error, null, 4) : error);
}
});
});
$(window).ready(() => {
setTimeout(defineTable, 500);
});
@ -275,6 +301,8 @@ $("input[name='filterActive']").on("change", () => {
const openSubForm = () => {
$("#subForm").removeClass("submitted");
$("#formPublishedThreshold").val(new Date().toISOString().slice(0, 16));
$("#formActive").prop("checked", true);
HSOverlay.open($("#subModal").get(0))
}
@ -291,10 +319,7 @@ const submitForm = async event => {
const form = $("#subForm").get(0);
$(form).addClass("submitted");
if (!form.checkValidity()) {
alert("form invalid");
return;
}
if (!form.checkValidity()) { return; }
await $.ajax({
url: `/guild/${guildId}/subscriptions/api`,

View File

@ -8,7 +8,7 @@
<div class="flex flex-col">
<div class="-m-1.5">
<div class="max-w-full p-1.5 min-w-full inline-block align-middle">
<div class="bg-white border border-gray-200 rounded-md shadow-sm overflow-hidden dark:bg-neutral-900 dark:border-neutral-700">
<div class="bg-white border border-gray-200 rounded-md shadow-sm overflow-hidden dark:bg-neutral-800 dark:border-neutral-700">
<!-- Header -->
<div class="px-6 py-4 gap-3 flex flex-nowrap justify-between items-center border-b border-gray-200 dark:border-neutral-700">
<!-- Input -->
@ -333,7 +333,7 @@
</select>
<p class="mt-2 text-sm text-gray-500 dark:text-neutral-500">
Ignore content older than this date.
Send content to these channels.
</p>
</div>
<div class="relative">
@ -357,7 +357,7 @@
<option>Filter 3</option>
</select>
<p class="mt-2 text-sm text-gray-500 dark:text-neutral-500">
Ignore content older than this date.
Filter out unwanted content.
</p>
</div>
<label for="formActive" class="flex gap-4">

View File

@ -18,12 +18,12 @@
<!-- <%- include("footer") -%> -->
<script src="/static/foreign/jquery.js"></script>
<script src="/static/foreign/dataTables.js"></script>
<script src="/static/foreign/dataTablesSelect.js"></script>
<script src="/static/foreign/popper.js"></script>
<script src="/static/foreign/preline.js"></script>
<script src="/static/js/main.js"></script>
<script type="text/javascript" src="/static/foreign/jquery.js"></script>
<script type="text/javascript" src="/static/foreign/dataTables.js"></script>
<script type="text/javascript" src="/static/foreign/dataTablesSelect.js"></script>
<script type="text/javascript" src="/static/foreign/popper.js"></script>
<script type="text/javascript" src="/static/foreign/preline.js"></script>
<script type="text/javascript" src="/static/js/main.js"></script>
<%- block("scripts").toString() %>
</body>
</html>

View File

@ -124,18 +124,24 @@ export const post = async (request: Request, response: Response) => {
export const del = async (request: Request, response: Response) => {
try {
let ids: any = request.query.id;
const { ids } = request.body;
const guild_id = request.params.guildId;
console.log(JSON.stringify(ids));
console.log(`deleting subs: ${ids}`);
if (!ids) {
response.status(400).json({ error: "missing 'id' query" });
if (!ids || !Array.isArray(ids)) {
response.status(400).json({ error: "invalid request body" });
return;
}
if (Array.isArray(ids)) {
ids = [ids];
const subscriptionsToDelete = await db<Subscription>(TABLE).whereIn("id", ids).select("guild_id");
if (subscriptionsToDelete.some(sub => sub.guild_id !== guild_id)) {
response.status(400).json({ error: `Some subscriptions do not belong to guild: ${guild_id}` });
return;
}
await db(TABLE).whereIn("id", ids).delete();
await db(TABLE).whereIn("id", ids).andWhere("guild_id", guild_id).delete();
response.status(204).json(null);
}
catch (error) {