2024-03-11 22:42:58 +00:00

517 lines
20 KiB
HTML

{% extends "layouts/base.html" %}
{% load static %}
{% block title %} Main Page {% endblock title %}
<!-- Specific CSS goes HERE -->
{% block stylesheets %}
<style>
.draw-border-success:hover {
color: var(--bs-success);
}
.draw-border-success:hover::before, .draw-border-success:hover::after {
border-color: var(--bs-success);
}
.draw-border-primary:hover {
color: var(--bs-primary);
}
.draw-border-primary:hover::before, .draw-border-primary:hover::after {
border-color: var(--bs-primary);
}
.draw-border-secondary:hover {
color: var(--bs-secondary);
}
.draw-border-secondary:hover::before, .draw-border-secondary:hover::after {
border-color: var(--bs-secondary);
}
.draw-border-danger:hover {
color: var(--bs-danger);
}
.draw-border-danger:hover::before, .draw-border-danger:hover::after {
border-color: var(--bs-danger);
}
.draw-border {
box-shadow: inset 0 0 0 1px var(--border-colour);
color: var(--bs-body-color);
transition: color 0.15s 0.0833333333s;
position: relative;
}
.draw-border::before, .draw-border::after {
border: 0 solid transparent;
box-sizing: border-box;
content: '';
pointer-events: none;
position: absolute;
width: 0;
height: 0;
bottom: 0;
right: 0;
}
.draw-border::before {
border-bottom-width: 1px;
border-left-width: 1px;
}
.draw-border::after {
border-top-width: 1px;
border-right-width: 1px;
}
.draw-border:hover::before, .draw-border:hover::after {
transition: border-color 0s, width 0.15s, height 0.15s;
width: 100%;
height: 100%;
}
.draw-border:hover::before {
transition-delay: 0s, 0s, 0.15s;
}
.draw-border:hover::after {
transition-delay: 0s, 0.15s, 0s;
}
/* modal tabs */
.modal-tabs {
background-color: var(--bs-tertiary-bg);
}
.modal-tabs .nav-link {
border-top: none;
border-radius: 0;
}
.modal-tabs .nav-link:first-child {
margin-left: 1rem;
}
.modal-tabs .nav-link:last-child {
margin-right: 1rem;
}
</style>
{% endblock stylesheets %}
{% block content %}
<!-- ### $App Screen Content ### -->
<main class="main-content bg-body-tertiary">
<div id="mainContent">
<!--
<div class="row gap-20 masonry pos-r">
<div class="masonry-sizer col-md-6"></div>
<div class="masonry-item col-12">
<div class="row gap-20"> -->
<!-- Total Subscriptions -->
<!-- <div class="col-md-3">
<div class="layers bd bg-body p-20">
<div class="layer w-100 mB-10">
<h6 class="lh-1">Total Subscriptions</h6>
</div>
<div class="layer w-100">
<div class="peers ai-sb fxw-nw">
<div class="peer peer-greed">
<span id="sparklinedash"></span>
</div>
<div class="peer">
<span class="d-ib lh-0 va-m fw-600 bdrs-10em pX-15 pY-15 bgc-green-50 c-green-500">
<span class="subs-count">--</span>
</span>
</div>
</div>
</div>
</div>
</div> -->
<!-- Subscription Activity (24hrs) -->
<!-- <div class="col-md-3">
<div class="layers bd bg-body p-20">
<div class="layer w-100 mB-10">
<h6 class="lh-1">Subscription Activity (24hrs)</h6>
</div>
<div class="layer w-100">
<div class="peers ai-sb fxw-nw">
<div class="peer peer-greed">
<span id="sparklinedash2"></span>
</div>
<div class="peer">
<span class="d-ib lh-0 va-m fw-600 bdrs-10em pX-15 pY-15 bgc-deep-purple-50 c-deep-purple-500">47</span>
</div>
</div>
</div>
</div>
</div> -->
<!-- </div>
</div>
<div class="masonry-item col-12">
<hr>
</div>
</div> -->
<div class="container-fluid mT-10 pX-0">
<div class="lh-1 pX-5 pB-20 peers">
<div class="peer peer-greed">
<h3 class="mB-0">Subscriptions</h3>
</div>
<div class="peer fs-5 fw-bold">
<button class="btn bg-body bdrs-2 mR-3 cur-p draw-border draw-border-success" onclick="subEditModal(-1);">
<i class="bi bi-plus"></i>
New Subscription
</button>
</div>
</div>
<div id="subscriptionContainer" class="row gap-20">
<!-- Subscriptions Here! -->
</div>
</div>
</div>
</main>
<div id="subEditModal" class="modal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1" aria-hidden="true">
<div class="modal-dialog">
<div class="modal-content bdrs-2 bd">
<div class="modal-header">
<h5 class="modal-title"></h5>
</div>
<nav>
<div class="nav nav-tabs modal-tabs" role="tablist">
<button id="navDetailsTab" class="nav-link" data-bs-toggle="tab" data-bs-target="#navDetailsPanel" type="button" role="tab" aria-controls="navDetailsPanel" aria-selected="true">Details</button>
<button id="navChannelTab" class="nav-link" data-bs-toggle="tab" data-bs-target="#navChannelPanel" type="button" role="tab" aria-controls="navChannelPanel" aria-selected="true">Channels</button>
<button id="navExtrasTab" class="nav-link" data-bs-toggle="tab" data-bs-target="#navExtrasPanel" type="button" role="tab" aria-controls="navExtrasPanel" aria-selected="true">Extras</button>
</div>
</nav>
<div class="modal-body">
<form id="subEditForm" class="needs-validation" novalidate>
<div class="tab-content">
<div id="navDetailsPanel" class="tab-pane fade" role="tabpanel" aria-labelledby="navDetailsTab" tabindex="0">
<div class="mb-3">
<label for="editSubName" class="form-label">Name</label>
<input type="text" name="editSubName" id="editSubName" class="form-control bdrs-2 bd" required maxlength="32">
<div class="invalid-feedback">Required, Maximum of 32 Characters.</div>
</div>
<div class="mb-3">
<label for="editSubURL" class="form-label">URL</label>
<input type="url" name="editSubURL" id="editSubURL" class="form-control bdrs-2 bd" required>
<div class="invalid-feedback">Please Enter a Valid URL.</div>
</div>
<div>
<label for="editSubImage" class="form-label">Image</label>
<input type="file" name="editSubImage" id="editSubImage" class="form-control bdrs-2 bd">
<div class="form-text">Optional</div>
<div class="invalid-feedback">This Image Is Invalid.</div>
</div>
</div>
<div id="navChannelPanel" class="tab-pane fade" role="tabpanel" aria-labelledby="navChannelTab" tabindex="0">
<div class="mb-3">
<label for="editSubServer" class="form-label">Server</label>
<select name="editSubServer" id="editSubServer" class="form-select bdrs-2 bd" required>
<option value="">Select a server</option>
</select>
<div class="form-help">Ensure that PYRSS Bot is a member of the selected server.</div>
<div class="invalid-feedback">Please Select a Server.</div>
</div>
<div>
<label for="editSubChannels">Channels</label>
<select name="editSubChannels" id="editSubChannels" class="form-select bdrs-2 bd" required multiple>
<option value="1039201459188805692">CodeHub</option>
<option value="753323563381031042">Orange</option>
<option value="1204426362794811453">PYRSS Home</option>
<option value="410208534861447168">Ryujinx</option>
</select>
</div>
</div>
<div id="navExtrasPanel" class="tab-pane fade" role="tabpanel" aria-labelledby="navExtrasTab" tabindex="0">
<div>
<label for="editSubNotes" class="form-label">Notes</label>
<textarea name="editSubNotes" id="editSubNotes" class="form-control" style="height: 200px;"></textarea>
</div>
</div>
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn bg-body-tertiary bdrs-2 cur-p draw-border draw-border-success" onclick="submitSubEditModal();">
<i class="bi bi-check me-1`"></i>
Submit
</button>
<button class="btn bg-body-tertiary bdrs-2 cur-p draw-border draw-border-secondary" data-bs-dismiss="modal">
<i class="bi bi-x me-1`"></i>
Cancel
</button>
</div>
</div>
</div>
</div>
{% endblock content %}
<!-- Specific Page JS goes HERE -->
{% block javascripts %}
<script id="subItemTemplate" type="text/template">
<div class="col-md-4 col-xxl-3">
<div class="sub-item layers bd bg-body h-100 rounded-3" data-uuid="">
<!-- <div class="layer w-100 bdB pb-4">
<div class="d-flex px-4">
<span class="h5 lh-1 sub-name mb-0"></span>
<img class="sub-img h-100">
</div>
</div>
<div class="layer w-100 py-4 px-4">
<p class="sub-desc mb-0"></p>
</div>
<div class="layer w-100 mb-3 px-4">
<span class=sub-uuid></span>
</div>
<div class="layer w-100 mb-3 px-4">
<a class="sub-rss"></a>
</div>
<div class="layer w-100 mb-3 px-4">
<img class="sub-img mw-100" height="75">
</div>
<div class="layer d-flex flex-wrap w-100 mt-auto bdT pb-3 px-4">
<div class="me-auto d-flex ai-c">
<div class="form-check">
<input type="checkbox" class="form-check-input mt-3" style="transform:scale(1.25);">
</div>
</div>
<div>
<button class="sub-edit btn btn-sm bg-body-tertiary bdrs-2 mt-3 cur-p draw-border draw-border-secondary">
<i class="bi bi-pencil me-1`"></i>
Edit
</button>
<button class="sub-delete btn btn-sm bg-body-tertiary bdrs-2 mt-3 cur-p draw-border draw-border-danger">
<i class="bi bi-trash me-1`"></i>
Delete
</button>
</div>
</div> -->
<div class="layer w-100">
<div class="peers p-4 flex-nowrap">
<div class="peer peer-greed me-4">
<h5 class="sub-name"></h5>
<span class="sub-uuid"></span>
</div>
<div class="peer">
<img src="" alt="" class="sub-img">
</div>
</div>
</div>
<div class="w-50 align-self-start bd mx-4"></div>
<div class="layer w-100 p-4">
<p class="sub-desc mb-4"></p>
<a class="sub-rss"></a>
</div>
<div class="layer w-100 bdT p-4 mt-auto">
<div class="peers ai-c">
<div class="peer peer-greed">
<div class="form-check form-switch ms-2">
<input type="checkbox" name="" id="" class="form-check-input" style="transform: scale(1.5);">
</div>
</div>
<div class="peer">
<button class="sub-edit btn bg-body-tertiary rounded-3">
<i class="bi bi-pencil me-1"></i>
Edit
</button>
</div>
<div class="peer ms-3">
<button class="sub-delete btn bg-body-tertiary rounded-3">
<i class="bi bi-trash3 me-1"></i>
Delete
</button>
</div>
</div>
</div>
</div>
</div>
</script>
<script src="{% static 'js/api.js' %}"></script>
<script type="text/javascript">
function createSubscriptionItem(data) {
var template = $($("#subItemTemplate").html());
template.find(".sub-item").attr("data-uuid", data.uuid);
template.find(".sub-name").text(data.name);
template.find(".sub-uuid").text(data.uuid);
template.find(".sub-rss").text(data.rss_url).attr("href", data.rss_url);
template.find(".sub-img").attr("src", data.image);
template.find(".sub-desc").text(data.extra_notes);
template.find(".sub-edit").attr("onclick", `subEditModal("${data.uuid}");`);
template.find(".sub-delete").attr("onclick", `unsubscribe("${data.uuid}");`);
return template
}
$(document).ready(function() {
loadGuilds();
loadSubscriptions();
$("#editSubServer").change(function() {
loadChannels($(this).find("option:selected").attr("value"));
});
});
function loadGuilds() {
$.ajax({
url: "/guilds",
type: "GET",
success: function(response) {
for (i = 1; i < response.length; i++) {
var guild = response[i];
$("#editSubServer").append($("<option>", {
value: guild.id,
text: guild.name
}));
}
},
error: function(response) {
alert(JSON.stringify(response, null, 4));
}
});
}
function loadChannels(guildID) {
$("#editSubChannels").empty();
$.ajax({
url: `/channels?guild=${guildID}`,
type: "GET",
success: function(response) {
for (i = 1; i < response.length; i++) {
var channel = response[i];
if (channel.type !== 0) {
continue
}
var selectedChannelIDs = $("#editSubChannels").attr("data-current").split(";");
$("#editSubChannels").append($("<option>", {
value: channel.id,
text: "#" + channel.name,
selected: selectedChannelIDs.includes(channel.id.toString())
}));
}
},
error: function(response) {
console.error(JSON.stringify(response, null, 4));
if (response.code == "50001") {
alert("PYRSS Bot is Missing Access to this Server");
}
else {
alert("unknown error fetching channels " + response.code)
}
}
});
}
function updateSubscriptionCount(difference, overwrite) {
const beforeChange = overwrite ? 0 : Number($(".subs-count").text());
$(".subs-count").text(beforeChange + difference);
}
function loadSubscriptions() {
$("#subscriptionContainer").empty();
getSubscriptions().then(resp => {
updateSubscriptionCount(resp.results.length, true);
for (i = 0; i < resp.results.length; i++) {
var sub = resp.results[i];
console.log(JSON.stringify(sub));
var subElem = createSubscriptionItem(sub);
$("#subscriptionContainer").append(subElem);
}
});
}
function unsubscribe(uuid) {
var subElem = $(`#subscriptionContainer .sub-item[data-uuid="${uuid}"]`);
subElem.find("button").prop("disabled", true);
deleteSubscription(uuid).then(resp => {
subElem.parent().remove();
updateSubscriptionCount(-1);
});
}
function subEditModal(uuid) {
var modal = $("#subEditModal");
modal.find("input").val(null);
modal.find("textarea").val(null);
modal.find("select").val("");
$("#editSubChannels").empty();
$("#subEditForm").removeClass("was-validated");
$("#navDetailsTab").click();
if (uuid === -1) {
modal.find(".modal-title").text("New Subscription");
}
else {
modal.find(".modal-title").text("Edit Subscription");
getSubscription(uuid).then(resp => {
// alert(JSON.stringify(resp, null, 4));
$("#editSubName").val(resp.name);
$("#editSubURL").val(resp.rss_url);
$("#editSubServer").val(String(resp.server)).trigger("change");
$("#editSubChannels").attr("data-current", resp.targets);
$("#editSubNotes").val(resp.extra_notes);
});
}
$("#subEditModal").attr("data-uuid", uuid);
$("#subEditModal").modal("show");
}
function submitSubEditModal() {
// Validation
var form = $("#subEditForm");
if (!form[0].checkValidity()) {
form.addClass("was-validated");
return;
}
const uuid = $("#subEditModal").attr("data-uuid");
var formData = new FormData();
formData.append("uuid", uuid);
formData.append("name", $("#editSubName").val());
formData.append("rss_url", $("#editSubURL").val());
formData.append("server", $("#editSubServer").val());
formData.append("extra_notes", $("#editSubNotes").val());
var selectedTargets = $("#editSubChannels option:selected").toArray().map(item => item.value).join(';');
formData.append("targets", selectedTargets);
var imageFile = $("#editSubImage")[0].files[0];
if (imageFile) {
formData.append("image", imageFile);
}
if (uuid === "-1") {
newSubscription(formData).then(resp => {
loadSubscriptions();
$("#subEditModal").modal("hide");
})
}
else {
editSubscription(uuid, formData).then(resp => {
loadSubscriptions();
$("#subEditModal").modal("hide");
});
}
}
</script>
{% endblock javascripts %}