Spaces:
Running
Running
{% extends "base.html" %} | |
{% block title %} | |
Moderate Comments - {{ video.title }} | |
{% endblock %} | |
{% block content %} | |
<div class="container mx-auto px-4 py-8"> | |
<!-- Outer container with card styling --> | |
<div class="bg-white shadow-xl rounded-lg overflow-visible"> | |
<!-- Header section with video title and controls --> | |
<div class="bg-gradient-to-r from-blue-500 to-purple-600 p-6"> | |
<div class="flex justify-between items-center"> | |
<h1 class="text-3xl font-bold text-white flex items-center"> | |
<i class="fab fa-youtube mr-4 text-red-500"></i> | |
{{ video.title }} | |
</h1> | |
<div class="flex space-x-4"> | |
<button id="refreshCommentsBtn" class="bg-white text-blue-600 px-4 py-2 rounded-lg hover:bg-blue-50 transition duration-300 flex items-center shadow-md"> | |
<i class="fas fa-sync mr-2"></i>Refresh Comments | |
</button> | |
<div x-data="{ showSettings: false, saveSettings() { | |
// Add your save logic here, e.g., update a model or call an API | |
alert('Settings saved!'); | |
this.showSettings = false; // Optionally hide the settings box after saving | |
} }" class="relative"> | |
<button @click="showSettings = !showSettings" class="bg-white text-purple-600 px-4 py-2 rounded-lg hover:bg-purple-50 transition duration-300 flex items-center shadow-md"> | |
<i class="fas fa-cog mr-2"></i>Moderation Settings | |
</button> | |
<div x-show="showSettings" x-transition class="absolute right-0 mt-2 w-72 bg-white rounded-lg shadow-2xl p-6 z-20 border border-gray-100"> | |
<h3 class="text-xl font-semibold mb-4 text-gray-800">Moderation Settings</h3> | |
<div class="space-y-4"> | |
<div class="flex items-center"> | |
<input type="checkbox" id="auto-delete" class="mr-3 rounded text-blue-500 focus:ring-blue-400"> | |
<label for="auto-delete" class="text-gray-700">Auto-delete flagged comments</label> | |
</div> | |
<div> | |
<label class="block mb-2 text-gray-700">Gambling Confidence Threshold</label> | |
<input type="range" min="0" max="1" step="0.05" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer" x-model="threshold" value="0.55"> | |
</div> | |
<button @click="saveSettings" class="w-full bg-gradient-to-r from-blue-500 to-purple-600 text-white py-2 rounded-lg hover:opacity-90 transition duration-300"> | |
Save Settings | |
</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Comments Section --> | |
<div class="grid md:grid-cols-2 gap-6 p-6"> | |
<!-- Safe Comments Column --> | |
<div> | |
<h2 class="text-2xl font-semibold mb-4 flex items-center text-green-600"> | |
<i class="fas fa-check-circle mr-3"></i>Safe Comments | |
<span class="text-sm text-gray-500 ml-2">({{ safe_comments|length }})</span> | |
</h2> | |
<div class="space-y-4"> | |
{% for comment in safe_comments %} | |
<div class="bg-white p-4 rounded-lg shadow-md border border-gray-100"> | |
<p class="mb-2 text-gray-800">{{ comment.text }}</p> | |
<div class="text-sm text-gray-600 flex justify-between items-center"> | |
<span class="font-medium">{{ comment.author }}</span> | |
<span class="text-xs text-green-600">Safe</span> | |
</div> | |
</div> | |
{% endfor %} | |
</div> | |
</div> | |
<!-- Flagged Comments Column --> | |
<div> | |
<h2 class="text-2xl font-semibold mb-4 flex items-center text-red-600"> | |
<i class="fas fa-exclamation-triangle mr-3"></i>Flagged Comments | |
<span id="flaggedCount" class="text-sm text-gray-500 ml-2">({{ flagged_comments|length }})</span> | |
</h2> | |
<div class="space-y-4"> | |
{% for comment in flagged_comments %} | |
<div class="comment-card bg-red-50 p-4 rounded-lg shadow-md border border-red-200 relative"> | |
<p class="mb-2 text-gray-800">{{ comment.text }}</p> | |
<div class="text-sm text-gray-600 flex justify-between items-center"> | |
<span class="font-medium">{{ comment.author }}</span> | |
<div class="flex space-x-2"> | |
<button data-comment-id="{{ comment.id }}" data-video-id="{{ video.id }}" class="delete-comment-btn bg-red-500 text-white px-3 py-1 rounded hover:bg-red-600 transition duration-300"> | |
Delete | |
</button> | |
<button data-comment-id="{{ comment.id }}" data-video-id="{{ video.id }}"class="keep-comment-btn bg-green-500 text-white px-3 py-1 rounded hover:bg-green-600 transition duration-300"> | |
Keep | |
</button> | |
</div> | |
</div> | |
<div class="mt-2 text-xs text-gray-500"> | |
<strong>Gambling Confidence:</strong> {{ comment.metrics.confidence_score }} | |
</div> | |
</div> | |
{% endfor %} | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
{% endblock %} | |
{% block scripts %} | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
// Delete Comment Functionality | |
document.querySelectorAll('.delete-comment-btn').forEach(button => { | |
button.addEventListener('click', async function(e) { | |
e.stopPropagation(); // Ensure this click doesn't affect other handlers | |
const commentId = this.getAttribute('data-comment-id'); | |
const videoId = this.getAttribute('data-video-id'); | |
const commentCard = this.closest('.comment-card'); | |
try { | |
const response = await fetch(`/api/comments/${commentId}?video_id=${videoId}`, { | |
method: 'DELETE' | |
}); | |
const data = await response.json(); | |
if (data.success) { | |
// Remove the comment from the DOM | |
commentCard.remove(); | |
// Optionally, update the flagged comments count | |
const flaggedCommentsCount = document.querySelector('h2 span'); | |
const currentCount = parseInt(flaggedCommentsCount.textContent.replace(/[()]/g, '')); | |
flaggedCommentsCount.textContent = `(${currentCount - 1})`; | |
} else { | |
alert("Failed to delete comment. Please refresh and try again."); | |
} | |
} catch (err) { | |
console.error(err); | |
alert("Error deleting comment."); | |
} | |
}); | |
}); | |
// Keep Comment Functionality with added debug logging | |
document.querySelectorAll('.keep-comment-btn').forEach(button => { | |
button.addEventListener('click', async function(e) { | |
e.stopPropagation(); | |
const commentId = this.getAttribute('data-comment-id'); | |
const videoId = this.getAttribute('data-video-id'); | |
const commentCard = this.closest('.comment-card'); | |
console.log(`Keep button clicked for commentId: ${commentId}, videoId: ${videoId}`); | |
try { | |
// Make the API call to keep the comment on YouTube | |
const response = await fetch(`/api/comments/keep/${commentId}?video_id=${videoId}`, { | |
method: 'POST' | |
}); | |
console.log("Response received from API:", response); | |
const data = await response.json(); | |
console.log("Parsed response data:", data); | |
if (data.success) { | |
// If successful, remove from DOM and update the flagged count | |
commentCard.remove(); | |
const flaggedCommentsCount = document.querySelector('#flaggedCount'); | |
const currentCount = parseInt(flaggedCommentsCount.textContent); | |
flaggedCommentsCount.textContent = currentCount - 1; | |
console.log(`Comment ${commentId} removed, flagged count updated to ${currentCount - 1}`); | |
} else { | |
console.error(`API reported error for comment ${commentId}:`, data.error); | |
alert("Failed to keep comment: " + (data.error || 'Unknown error')); | |
} | |
} catch (err) { | |
console.error(`Error keeping comment ${commentId}:`, err); | |
alert("Error keeping comment."); | |
} | |
}); | |
}); | |
// Refresh Comments Functionality | |
document.getElementById('refreshCommentsBtn').addEventListener('click', function(e) { | |
e.stopPropagation(); // Prevent any unwanted event bubbling | |
const videoId = "{{ video.id }}"; | |
window.location.href = `/video/${videoId}`; | |
}); | |
}); | |
</script> | |
{% endblock %} | |