mirror of
https://github.com/NNTmux/newznab-tmux.git
synced 2026-08-29 01:08:56 +00:00
219 lines
6.7 KiB
JavaScript
219 lines
6.7 KiB
JavaScript
/**
|
|
* Alpine.data('releaseReport') - Shared release report modal (singleton)
|
|
* Alpine.data('adminReleaseReports') - Admin release reports page
|
|
*
|
|
* Uses document-level click delegation in init() so that .report-trigger
|
|
* buttons anywhere on the page can open the single shared modal.
|
|
*/
|
|
import Alpine from '@alpinejs/csp';
|
|
|
|
Alpine.data('releaseReport', () => ({
|
|
open: false,
|
|
releaseId: '',
|
|
reason: '',
|
|
description: '',
|
|
isSubmitting: false,
|
|
errorMsg: '',
|
|
successMsg: '',
|
|
_currentTrigger: null,
|
|
|
|
openModal(releaseId, trigger) {
|
|
this.releaseId = releaseId;
|
|
this._currentTrigger = trigger || null;
|
|
this.reason = '';
|
|
this.description = '';
|
|
this.errorMsg = '';
|
|
this.successMsg = '';
|
|
this.isSubmitting = false;
|
|
this.open = true;
|
|
},
|
|
|
|
close() {
|
|
this.open = false;
|
|
},
|
|
|
|
charCount() {
|
|
return this.description.length + '/1000 characters';
|
|
},
|
|
|
|
canSubmit() {
|
|
return !!this.reason && !this.isSubmitting;
|
|
},
|
|
|
|
submitText() {
|
|
return this.isSubmitting ? 'Submitting...' : 'Submit Report';
|
|
},
|
|
|
|
submit() {
|
|
if (this.isSubmitting || !this.reason || !this.releaseId) return;
|
|
this.isSubmitting = true;
|
|
this.errorMsg = '';
|
|
this.successMsg = '';
|
|
|
|
var self = this;
|
|
var csrf = document.querySelector('meta[name="csrf-token"]')?.content || '';
|
|
var triggerRef = this._currentTrigger;
|
|
|
|
fetch('/release-report', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': csrf, 'Accept': 'application/json' },
|
|
body: JSON.stringify({ release_id: self.releaseId, reason: self.reason, description: self.description })
|
|
})
|
|
.then(function(r) { return r.json().then(function(data) { return { ok: r.ok, data: data }; }); })
|
|
.then(function(result) {
|
|
if (result.ok && result.data.success) {
|
|
self.successMsg = result.data.message;
|
|
// Mark the trigger button as reported
|
|
if (triggerRef) {
|
|
triggerRef.disabled = true;
|
|
triggerRef.classList.add('opacity-50', 'cursor-not-allowed');
|
|
var icon = triggerRef.querySelector('i');
|
|
if (icon) icon.classList.add('text-red-500');
|
|
var label = triggerRef.querySelector('.report-label');
|
|
if (label) label.textContent = 'Reported';
|
|
}
|
|
setTimeout(function() { self.close(); }, 2000);
|
|
} else {
|
|
self.errorMsg = result.data.message || 'An error occurred. Please try again.';
|
|
}
|
|
})
|
|
.catch(function() { self.errorMsg = 'Network error. Please try again.'; })
|
|
.finally(function() { self.isSubmitting = false; });
|
|
},
|
|
|
|
init() {
|
|
var self = this;
|
|
|
|
// Document-level click delegation for .report-trigger buttons
|
|
document.addEventListener('click', function(e) {
|
|
var trigger = e.target.closest('.report-trigger');
|
|
if (!trigger) return;
|
|
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
|
|
var releaseId = trigger.getAttribute('data-report-release-id');
|
|
if (!releaseId) return;
|
|
|
|
self.openModal(releaseId, trigger);
|
|
});
|
|
|
|
// Close on Escape key
|
|
document.addEventListener('keydown', function(e) {
|
|
if (e.key === 'Escape' && self.open) self.close();
|
|
});
|
|
}
|
|
}));
|
|
|
|
Alpine.data('adminReleaseReports', () => ({
|
|
descModalOpen: false,
|
|
descContent: '',
|
|
descReason: '',
|
|
descReporter: '',
|
|
revertModalOpen: false,
|
|
revertActionUrl: '',
|
|
revertStatus: '',
|
|
responseModalOpen: false,
|
|
responseActionUrl: '',
|
|
responseContent: '',
|
|
responseIsPublic: true,
|
|
allChecked: false,
|
|
selectedCount: 0,
|
|
rootEl: null,
|
|
|
|
init() {
|
|
this.rootEl = this.$root;
|
|
this.syncSelectionState();
|
|
},
|
|
|
|
showDescription(description, reason, reporter) {
|
|
this.descContent = description || 'No additional details provided.';
|
|
this.descReason = reason || 'Unknown';
|
|
this.descReporter = reporter || 'Unknown';
|
|
this.descModalOpen = true;
|
|
},
|
|
|
|
closeDescription() { this.descModalOpen = false; },
|
|
|
|
showRevert(actionUrl, status) {
|
|
this.revertActionUrl = actionUrl;
|
|
this.revertStatus = status;
|
|
this.revertModalOpen = true;
|
|
},
|
|
|
|
closeRevert() { this.revertModalOpen = false; },
|
|
|
|
submitRevert() {
|
|
const form = this.$refs.revertForm;
|
|
if (form) { form.action = this.revertActionUrl; form.submit(); }
|
|
},
|
|
|
|
showResponse(actionUrl, response, isPublic) {
|
|
this.responseActionUrl = actionUrl;
|
|
this.responseContent = response || '';
|
|
this.responseIsPublic = isPublic !== false;
|
|
this.responseModalOpen = true;
|
|
},
|
|
|
|
closeResponse() { this.responseModalOpen = false; },
|
|
|
|
responseCharCount() {
|
|
return (this.responseContent || '').length;
|
|
},
|
|
|
|
submitResponse() {
|
|
const form = this.$refs.responseForm;
|
|
if (form) { form.action = this.responseActionUrl; form.submit(); }
|
|
},
|
|
|
|
componentRoot() {
|
|
return this.rootEl || this.$root;
|
|
},
|
|
|
|
reportCheckboxes() {
|
|
const root = this.componentRoot();
|
|
return root ? [...root.querySelectorAll('.report-checkbox')] : [];
|
|
},
|
|
|
|
setAllSelection(checked) {
|
|
const boxes = this.reportCheckboxes();
|
|
boxes.forEach(cb => { cb.checked = checked; });
|
|
this.allChecked = checked && boxes.length > 0;
|
|
this.selectedCount = checked ? boxes.length : 0;
|
|
},
|
|
|
|
selectAll() {
|
|
this.setAllSelection(true);
|
|
},
|
|
|
|
clearSelection() {
|
|
this.setAllSelection(false);
|
|
},
|
|
|
|
toggleAll() {
|
|
this.setAllSelection(this.allChecked);
|
|
},
|
|
|
|
syncSelectionState() {
|
|
const boxes = this.reportCheckboxes();
|
|
const checkedCount = boxes.filter(cb => cb.checked).length;
|
|
this.selectedCount = checkedCount;
|
|
this.allChecked = boxes.length > 0 && checkedCount === boxes.length;
|
|
},
|
|
|
|
onCheckboxChange() {
|
|
this.syncSelectionState();
|
|
},
|
|
|
|
validateBulkAction(e) {
|
|
const action = this.componentRoot()?.querySelector('select[name="action"]')?.value;
|
|
const checkedCount = this.reportCheckboxes().filter(cb => cb.checked).length;
|
|
if (!action) { e.preventDefault(); alert('Please select an action.'); return; }
|
|
if (checkedCount === 0) { e.preventDefault(); alert('Please select at least one report.'); return; }
|
|
if (action === 'delete') {
|
|
if (!confirm('Are you sure you want to DELETE ' + checkedCount + ' release(s)? This action cannot be undone.')) e.preventDefault();
|
|
}
|
|
}
|
|
}));
|
|
|