mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-11-08 13:52:58 +00:00
submissions(#23): admin "Submissions" sub-tab (approve/deny)
The headline: an admin surface to triage the structured submissions. - profile-modal.html: "Submissions" sub-tab button + #adminSubmissionsSection (refresh + loading/empty + list), alongside Whitelist/Blacklist/Blocked videos/Moderators. - ProfileAdminController: adds "submissions" to the sub-tab machinery (button + section maps, selectAdminSubtab dispatch, refreshAdminPaneState populate), gates the tab on FEATURE_SUBMISSIONS, and wires the list/refresh listeners. - js/ui/profileModal/submissionsSection.js (extracted to keep the controller under the 1200-line cap, like blockedVideosSection.js): populate/render + approve/deny. Approve (applications only) → accessControl.addToWhitelist(actor, applicant) + markSubmissionResolved(approved) + refresh the whitelist; Deny/Dismiss → markSubmissionResolved(denied). Optimistic remove; re-sync on failure. Cards show the type badge + claimed applicant + body. - tailwind.source.css: .submission-card* (token-only). Gated by FEATURE_SUBMISSIONS (tab hidden when off). Lint + build clean; profile-modal-controller tests 26/26. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
1 parent
28b23e0078
commit
2a21756842
4 files changed
+378
-2
No files matched your search
@@ -7,12 +7,23 @@ import {
|
||||
renderBlockedVideosList,
|
||||
} from "./blockedVideosSection.js";
|
||||
import { showConfirm } from "../confirmDialog.js";
|
||||
import { FEATURE_SUBMISSIONS } from "../../constants.js";
|
||||
import {
|
||||
populateSubmissions,
|
||||
handleSubmissionsClick,
|
||||
} from "./submissionsSection.js";
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
// Admin pane sub-tabs, in toolbar order. "moderators" is only shown to the
|
||||
// super admin (its tab button is hidden otherwise).
|
||||
const ADMIN_SUBTABS = ["whitelist", "blacklist", "blockedVideos", "moderators"];
|
||||
// super admin; "submissions" only when FEATURE_SUBMISSIONS is on.
|
||||
const ADMIN_SUBTABS = [
|
||||
"whitelist",
|
||||
"blacklist",
|
||||
"blockedVideos",
|
||||
"moderators",
|
||||
"submissions",
|
||||
];
|
||||
const DEFAULT_ADMIN_SUBTAB = "whitelist";
|
||||
|
||||
export class ProfileAdminController {
|
||||
@@ -84,18 +95,27 @@ export class ProfileAdminController {
|
||||
this.blockedVideoInput = document.getElementById("adminBlockedVideoInput") || null;
|
||||
this.blockedVideosRefreshBtn = document.getElementById("adminBlockedVideosRefreshBtn") || null;
|
||||
|
||||
this.submissionsSection = document.getElementById("adminSubmissionsSection") || null;
|
||||
this.submissionsList = document.getElementById("adminSubmissionsList") || null;
|
||||
this.submissionsEmpty = document.getElementById("adminSubmissionsEmpty") || null;
|
||||
this.submissionsLoading = document.getElementById("adminSubmissionsLoading") || null;
|
||||
this.submissionsRefreshBtn = document.getElementById("adminSubmissionsRefreshBtn") || null;
|
||||
this.pendingSubmissions = [];
|
||||
|
||||
this.subtabBar = document.getElementById("adminSubtabBar") || null;
|
||||
this.subtabButtons = {
|
||||
whitelist: document.getElementById("adminSubtabWhitelist") || null,
|
||||
blacklist: document.getElementById("adminSubtabBlacklist") || null,
|
||||
blockedVideos: document.getElementById("adminSubtabBlockedVideos") || null,
|
||||
moderators: document.getElementById("adminSubtabModerators") || null,
|
||||
submissions: document.getElementById("adminSubtabSubmissions") || null,
|
||||
};
|
||||
this.subtabSections = {
|
||||
whitelist: this.whitelistSection,
|
||||
blacklist: this.blacklistSection,
|
||||
blockedVideos: this.blockedVideosSection,
|
||||
moderators: this.moderatorSection,
|
||||
submissions: this.submissionsSection,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -212,6 +232,17 @@ export class ProfileAdminController {
|
||||
}
|
||||
}
|
||||
|
||||
if (this.submissionsRefreshBtn instanceof HTMLElement) {
|
||||
this.submissionsRefreshBtn.addEventListener("click", () => {
|
||||
void populateSubmissions(this);
|
||||
});
|
||||
}
|
||||
if (this.submissionsList instanceof HTMLElement) {
|
||||
this.submissionsList.addEventListener("click", (event) =>
|
||||
handleSubmissionsClick(this, event),
|
||||
);
|
||||
}
|
||||
|
||||
if (this.addBlockedVideoButton instanceof HTMLElement) {
|
||||
this.addBlockedVideoButton.addEventListener("click", () => {
|
||||
void this.handleAddBlockedVideo();
|
||||
@@ -283,6 +314,10 @@ export class ProfileAdminController {
|
||||
section.setAttribute("aria-hidden", (!isActive).toString());
|
||||
}
|
||||
}
|
||||
|
||||
if (target === "submissions") {
|
||||
void populateSubmissions(this);
|
||||
}
|
||||
}
|
||||
|
||||
populateAdminLists() {
|
||||
@@ -566,8 +601,20 @@ export class ProfileAdminController {
|
||||
}
|
||||
}
|
||||
|
||||
// Submissions tab is only shown when the feature is enabled.
|
||||
const submissionsTab = this.subtabButtons?.submissions;
|
||||
if (submissionsTab instanceof HTMLElement) {
|
||||
submissionsTab.classList.toggle("hidden", !FEATURE_SUBMISSIONS);
|
||||
if (!FEATURE_SUBMISSIONS) {
|
||||
submissionsTab.setAttribute("aria-selected", "false");
|
||||
}
|
||||
}
|
||||
|
||||
this.populateAdminLists();
|
||||
this.populateBlockedVideos();
|
||||
if (FEATURE_SUBMISSIONS) {
|
||||
void populateSubmissions(this);
|
||||
}
|
||||
// Re-apply the current sub-tab so exactly one section is visible (and so a
|
||||
// now-hidden Moderators tab falls back to the default).
|
||||
this.selectAdminSubtab(this.activeSubtab);
|
||||
|
||||
Reference in new issue
Block a user