Sindbad~EG File Manager
<?php
require_once '../config/config.php';
require_once '../classes/Editorial.php';
require_once '../classes/User.php';
if (session_status() == PHP_SESSION_NONE) {
session_start();
}
if (!isset($_SESSION['user_id'])) {
header('Location: ../index.php');
exit();
}
// Check if user has editorial permissions
$allowed_types = ['editor', 'admin', 'superuser'];
if (!in_array($_SESSION['account_type'], $allowed_types)) {
header('Location: ../dashboard.php?error=access_denied');
exit();
}
$database = new Database();
$conn = $database->getConnection();
$editorial = new Editorial($conn);
$user = new User($conn);
// Handle AJAX requests
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_POST['action'])) {
header('Content-Type: application/json');
switch ($_POST['action']) {
case 'review_article':
$news_id = (int)$_POST['news_id'];
$review_action = $_POST['review_action']; // 'approve' or 'reject'
$comments = $_POST['comments'] ?? '';
$internal_notes = $_POST['internal_notes'] ?? '';
$result = $editorial->reviewArticle($news_id, $_SESSION['user_id'], $review_action, $comments, $internal_notes);
echo json_encode($result);
exit();
case 'bulk_review':
$article_ids = json_decode($_POST['article_ids'], true);
$review_action = $_POST['review_action'];
$comments = $_POST['comments'] ?? '';
$results = [];
foreach ($article_ids as $news_id) {
$result = $editorial->reviewArticle($news_id, $_SESSION['user_id'], $review_action, $comments);
$results[] = ['id' => $news_id, 'success' => $result['success']];
}
echo json_encode(['success' => true, 'results' => $results]);
exit();
}
}
// Get review queue and statistics
$review_queue = $editorial->getReviewQueue($_SESSION['user_id']);
$stats = $editorial->getEditorialStats($_SESSION['user_id']);
// Debug: Check if we have any articles available for review
$debug_query = "SELECT COUNT(*) as count FROM news WHERE status IN ('pending_review', 'draft')";
$debug_stmt = $conn->prepare($debug_query);
$debug_stmt->execute();
$debug_result = $debug_stmt->fetch(PDO::FETCH_ASSOC);
$total_pending = $debug_result['count'];
// Pagination for review queue
$page = isset($_GET['page']) ? (int)$_GET['page'] : 1;
$per_page = 10;
$total_articles = count($review_queue);
$total_pages = ceil($total_articles / $per_page);
$offset = ($page - 1) * $per_page;
$paginated_queue = array_slice($review_queue, $offset, $per_page);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Editorial Dashboard - COP News Portal</title>
<link rel="stylesheet" href="../assets/css/style.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css">
<style>
.stats-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 1rem;
margin-bottom: 2rem;
}
.stat-card {
background: white;
padding: 1.5rem;
border-radius: 8px;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
text-align: center;
}
.stat-number {
font-size: 2rem;
font-weight: bold;
color: var(--primary-color);
}
.stat-label {
color: #666;
margin-top: 0.5rem;
}
.review-actions {
display: flex;
gap: 0.5rem;
margin-top: 1rem;
}
.btn-approve {
background: #28a745;
color: white;
}
.btn-reject {
background: #dc3545;
color: white;
}
.bulk-actions {
background: #f8f9fa;
padding: 1rem;
border-radius: 6px;
margin-bottom: 1rem;
display: none;
}
.bulk-actions.active {
display: block;
}
.article-checkbox {
margin-right: 0.5rem;
}
.review-modal {
display: none;
position: fixed;
z-index: 1000;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-color: rgba(0,0,0,0.5);
}
.modal-content {
background-color: white;
margin: 5% auto;
padding: 2rem;
border-radius: 8px;
width: 90%;
max-width: 600px;
max-height: 80vh;
overflow-y: auto;
}
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
cursor: pointer;
}
.close:hover {
color: black;
}
.form-group {
margin-bottom: 1rem;
}
.form-group label {
display: block;
margin-bottom: 0.5rem;
font-weight: bold;
}
.form-group textarea {
width: 100%;
min-height: 100px;
padding: 0.5rem;
border: 1px solid #ddd;
border-radius: 4px;
resize: vertical;
}
</style>
</head>
<body>
<header class="header">
<nav class="navbar">
<a href="../dashboard.php" class="logo">
<i class="fas fa-church"></i> COP News Portal
</a>
<div class="nav-links">
<a href="../dashboard.php"><i class="fas fa-home"></i> Dashboard</a>
<a href="../news/index.php"><i class="fas fa-newspaper"></i> News</a>
<a href="dashboard.php" class="active"><i class="fas fa-edit"></i> Editorial</a>
<a href="approved.php"><i class="fas fa-check-circle"></i> Approved</a>
<a href="../profile.php"><i class="fas fa-user"></i> Profile</a>
<a href="../logout.php"><i class="fas fa-sign-out-alt"></i> Logout</a>
</div>
</nav>
</header>
<main class="container">
<div class="page-header">
<h1><i class="fas fa-edit"></i> Editorial Dashboard</h1>
<p>Review and manage articles awaiting editorial approval</p>
</div>
<!-- Editorial Statistics -->
<div class="stats-grid">
<div class="stat-card">
<div class="stat-number"><?= $stats['total_for_review'] ?? 0 ?></div>
<div class="stat-label">Available for Review</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $stats['draft'] ?? 0 ?></div>
<div class="stat-label">Draft Articles</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $stats['pending_review'] ?? 0 ?></div>
<div class="stat-label">Pending Review</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $stats['approved'] ?? 0 ?></div>
<div class="stat-label">Approved</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $stats['published'] ?? 0 ?></div>
<div class="stat-label">Published</div>
</div>
<div class="stat-card">
<div class="stat-number"><?= $stats['rejected'] ?? 0 ?></div>
<div class="stat-label">Rejected</div>
</div>
</div>
<!-- Review Queue -->
<div class="card">
<div class="card-header">
<h2><i class="fas fa-list-check"></i> Review Queue (<?= $total_articles ?> articles)</h2>
<div class="card-actions">
<button type="button" class="btn btn-secondary" onclick="toggleBulkActions()">
<i class="fas fa-tasks"></i> Bulk Actions
</button>
</div>
</div>
<!-- Debug Info -->
<?php if ($_SESSION['account_type'] === 'superuser'): ?>
<div style="background: #f8f9fa; padding: 1rem; margin: 1rem; border-radius: 4px; font-size: 0.9em;">
<strong>Debug Info:</strong> Total pending articles in system: <?= $total_pending ?> |
Articles in your queue: <?= $total_articles ?> |
Your role: <?= $_SESSION['account_type'] ?>
</div>
<?php endif; ?>
<!-- Bulk Actions Panel -->
<div class="bulk-actions" id="bulkActions">
<h4>Bulk Review Actions</h4>
<div style="display: flex; gap: 1rem; align-items: center;">
<button type="button" class="btn btn-approve" onclick="bulkReview('approve')">
<i class="fas fa-check"></i> Approve Selected
</button>
<button type="button" class="btn btn-reject" onclick="bulkReview('reject')">
<i class="fas fa-times"></i> Reject Selected
</button>
<input type="text" id="bulkComments" placeholder="Comments for all selected articles..." style="flex: 1; padding: 0.5rem;">
</div>
</div>
<div class="card-body">
<?php if (empty($paginated_queue)): ?>
<div class="empty-state">
<i class="fas fa-inbox"></i>
<h3>No Articles to Review</h3>
<p>All articles in your editorial scope have been reviewed.</p>
</div>
<?php else: ?>
<div class="table-responsive">
<table class="table">
<thead>
<tr>
<th><input type="checkbox" id="selectAll" onchange="toggleSelectAll()"></th>
<th>Title</th>
<th>Author</th>
<th>Location</th>
<th>Submitted</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
<?php foreach ($paginated_queue as $article): ?>
<tr>
<td>
<input type="checkbox" class="article-checkbox" value="<?= $article['id'] ?>" onchange="updateBulkActions()">
</td>
<td>
<strong><?= htmlspecialchars($article['title']) ?></strong>
<br>
<small class="text-muted"><?= htmlspecialchars(substr($article['description'], 0, 100)) ?>...</small>
</td>
<td><?= htmlspecialchars($article['author_name'] ?? 'Unknown') ?></td>
<td><?= htmlspecialchars($article['location_name'] ?? 'N/A') ?></td>
<td><?= $article['submitted_for_review_at'] ? date('M j, Y g:i A', strtotime($article['submitted_for_review_at'])) : 'N/A' ?></td>
<td>
<div class="review-actions">
<a href="../news/edit.php?id=<?= $article['id'] ?>" class="btn btn-sm btn-secondary" title="Edit Article">
<i class="fas fa-edit"></i>
</a>
<button type="button" class="btn btn-sm btn-primary" onclick="openReviewModal(<?= $article['id'] ?>, '<?= htmlspecialchars($article['title'], ENT_QUOTES) ?>')">
<i class="fas fa-eye"></i> Review
</button>
<button type="button" class="btn btn-sm btn-approve" onclick="quickReview(<?= $article['id'] ?>, 'approve')">
<i class="fas fa-check"></i>
</button>
<button type="button" class="btn btn-sm btn-reject" onclick="quickReview(<?= $article['id'] ?>, 'reject')">
<i class="fas fa-times"></i>
</button>
</div>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<!-- Pagination -->
<?php if ($total_pages > 1): ?>
<div class="pagination-wrapper">
<div class="pagination">
<?php for ($i = 1; $i <= $total_pages; $i++): ?>
<a href="?page=<?= $i ?>" class="<?= $i === $page ? 'active' : '' ?>"><?= $i ?></a>
<?php endfor; ?>
</div>
</div>
<?php endif; ?>
<?php endif; ?>
</div>
</div>
</main>
<!-- Review Modal -->
<div id="reviewModal" class="review-modal">
<div class="modal-content">
<span class="close" onclick="closeReviewModal()">×</span>
<h2 id="modalTitle">Review Article</h2>
<form id="reviewForm">
<input type="hidden" id="modalNewsId" name="news_id">
<div class="form-group">
<label>Review Decision:</label>
<div style="display: flex; gap: 1rem;">
<label style="font-weight: normal;">
<input type="radio" name="review_action" value="approve" required> Approve
</label>
<label style="font-weight: normal;">
<input type="radio" name="review_action" value="reject" required> Reject
</label>
</div>
</div>
<div class="form-group">
<label for="modalComments">Comments (visible to author):</label>
<textarea id="modalComments" name="comments" placeholder="Provide feedback to the author..."></textarea>
</div>
<div class="form-group">
<label for="modalInternalNotes">Internal Notes (editorial use only):</label>
<textarea id="modalInternalNotes" name="internal_notes" placeholder="Internal notes for editorial team..."></textarea>
</div>
<div style="display: flex; gap: 1rem; justify-content: flex-end;">
<button type="button" class="btn btn-secondary" onclick="closeReviewModal()">Cancel</button>
<button type="submit" class="btn btn-primary">Submit Review</button>
</div>
</form>
</div>
</div>
<script>
let selectedArticles = [];
function toggleBulkActions() {
const bulkActions = document.getElementById('bulkActions');
bulkActions.classList.toggle('active');
}
function toggleSelectAll() {
const selectAll = document.getElementById('selectAll');
const checkboxes = document.querySelectorAll('.article-checkbox');
checkboxes.forEach(checkbox => {
checkbox.checked = selectAll.checked;
});
updateBulkActions();
}
function updateBulkActions() {
const checkboxes = document.querySelectorAll('.article-checkbox:checked');
selectedArticles = Array.from(checkboxes).map(cb => cb.value);
const selectAll = document.getElementById('selectAll');
const allCheckboxes = document.querySelectorAll('.article-checkbox');
if (selectedArticles.length === 0) {
selectAll.indeterminate = false;
selectAll.checked = false;
} else if (selectedArticles.length === allCheckboxes.length) {
selectAll.indeterminate = false;
selectAll.checked = true;
} else {
selectAll.indeterminate = true;
}
}
function bulkReview(action) {
if (selectedArticles.length === 0) {
alert('Please select articles to review.');
return;
}
const comments = document.getElementById('bulkComments').value;
if (!confirm(`Are you sure you want to ${action} ${selectedArticles.length} article(s)?`)) {
return;
}
fetch('dashboard.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
action: 'bulk_review',
article_ids: JSON.stringify(selectedArticles),
review_action: action,
comments: comments
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert(`Successfully ${action}ed ${selectedArticles.length} article(s).`);
location.reload();
} else {
alert('Error processing bulk review. Please try again.');
}
})
.catch(error => {
console.error('Error:', error);
alert('Error processing request.');
});
}
function quickReview(newsId, action) {
if (!confirm(`Are you sure you want to ${action} this article?`)) {
return;
}
fetch('dashboard.php', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
},
body: new URLSearchParams({
action: 'review_article',
news_id: newsId,
review_action: action,
comments: `Quick ${action} from editorial dashboard`
})
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert(`Article ${action}ed successfully.`);
location.reload();
} else {
alert(data.error || 'Error processing review.');
}
})
.catch(error => {
console.error('Error:', error);
alert('Error processing request.');
});
}
function openReviewModal(newsId, title) {
document.getElementById('modalNewsId').value = newsId;
document.getElementById('modalTitle').textContent = `Review: ${title}`;
document.getElementById('reviewModal').style.display = 'block';
}
function closeReviewModal() {
document.getElementById('reviewModal').style.display = 'none';
document.getElementById('reviewForm').reset();
}
document.getElementById('reviewForm').addEventListener('submit', function(e) {
e.preventDefault();
const formData = new FormData(this);
formData.append('action', 'review_article');
fetch('dashboard.php', {
method: 'POST',
body: formData
})
.then(response => response.json())
.then(data => {
if (data.success) {
alert('Review submitted successfully.');
closeReviewModal();
location.reload();
} else {
alert(data.error || 'Error submitting review.');
}
})
.catch(error => {
console.error('Error:', error);
alert('Error processing request.');
});
});
// Close modal when clicking outside
window.onclick = function(event) {
const modal = document.getElementById('reviewModal');
if (event.target === modal) {
closeReviewModal();
}
}
</script>
</body>
</html>
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists