- Fixed author display to show single @ (was showing @@account) - Made status text clickable linking to full Mastodon post - Fixed author links to point to Mastodon instances instead of Bluesky 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
769 lines
20 KiB
HTML
769 lines
20 KiB
HTML
{% extends "base.html" %}
|
|
|
|
{% block title %}Flagged Content{% endblock %}
|
|
|
|
{% block content %}
|
|
<div class="flagged-container">
|
|
<!-- Page Header -->
|
|
<div class="page-header">
|
|
<h1>Flagged Content</h1>
|
|
<span class="total-badge">{{ total | format_number }}</span>
|
|
</div>
|
|
|
|
<!-- Filter Bar -->
|
|
<div class="filter-bar">
|
|
<form method="get" action="{{ url_for('analysis_flagged') }}" class="filter-form">
|
|
<div class="filter-group">
|
|
<label for="content-type">Type:</label>
|
|
<select id="content-type" name="content_type" class="filter-select">
|
|
<option value="">All Types</option>
|
|
<option value="post" {% if content_type == 'post' %}selected{% endif %}>Post</option>
|
|
<option value="reply" {% if content_type == 'reply' %}selected{% endif %}>Reply</option>
|
|
<option value="mention" {% if content_type == 'mention' %}selected{% endif %}>Mention</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="filter-group">
|
|
<label for="category">Category:</label>
|
|
<select id="category" name="category" class="filter-select">
|
|
<option value="">All Categories</option>
|
|
{% for cat in categories %}
|
|
<option value="{{ cat }}" {% if category == cat %}selected{% endif %}>{{ cat }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
<div class="filter-group">
|
|
<label for="account-did">Account:</label>
|
|
<select id="account-did" name="account_did" class="filter-select">
|
|
<option value="">All Accounts</option>
|
|
{% for acc in accounts %}
|
|
<option value="{{ acc.did }}" {% if account_did == acc.did %}selected{% endif %}>{{ acc.handle }}</option>
|
|
{% endfor %}
|
|
</select>
|
|
</div>
|
|
|
|
<div class="filter-group">
|
|
<label for="threshold">Threshold:</label>
|
|
<input type="number" id="threshold" name="threshold" min="0.0" max="1.0" step="0.1" value="{{ threshold or 0.5 }}" class="filter-input" placeholder="0.5">
|
|
</div>
|
|
|
|
<div class="filter-group">
|
|
<label for="review-status">Review Status:</label>
|
|
<select id="review-status" name="review_status" class="filter-select">
|
|
<option value="">All</option>
|
|
<option value="unreviewed" {% if review_status == 'unreviewed' %}selected{% endif %}>Unreviewed</option>
|
|
<option value="correct" {% if review_status == 'correct' %}selected{% endif %}>✓ Correct</option>
|
|
<option value="incorrect" {% if review_status == 'incorrect' %}selected{% endif %}>✗ Incorrect</option>
|
|
<option value="unsure" {% if review_status == 'unsure' %}selected{% endif %}>? Unsure</option>
|
|
</select>
|
|
</div>
|
|
|
|
<div class="filter-group">
|
|
<label for="date-from">From Date:</label>
|
|
<input type="date" id="date-from" name="date_from" value="{{ date_from or '' }}" class="filter-input">
|
|
</div>
|
|
|
|
<div class="filter-group">
|
|
<label for="date-to">To Date:</label>
|
|
<input type="date" id="date-to" name="date_to" value="{{ date_to or '' }}" class="filter-input">
|
|
</div>
|
|
|
|
<button type="submit" class="btn-apply">Apply Filters</button>
|
|
</form>
|
|
</div>
|
|
|
|
<!-- Content Table -->
|
|
{% if items %}
|
|
|
|
{% macro sort_header(col, label) %}
|
|
{% set new_dir = 'asc' if (sort == col and direction == 'desc') else 'desc' %}
|
|
<a href="{{ url_for('analysis_flagged', content_type=content_type, category=category, account_did=account_did, threshold=threshold, review_status=review_status, date_from=date_from, date_to=date_to, sort=col, dir=new_dir) }}" class="sort-link">
|
|
{{ label }}
|
|
{% if sort == col %}
|
|
<span class="sort-icon">{{ '▼' if direction == 'desc' else '▲' }}</span>
|
|
{% endif %}
|
|
</a>
|
|
{% endmacro %}
|
|
|
|
<div class="table-wrapper">
|
|
<table class="flagged-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Type</th>
|
|
<th>{{ sort_header('author_handle', 'Author') }}</th>
|
|
<th>Content</th>
|
|
<th>{{ sort_header('overall', 'Score') }}</th>
|
|
<th>Category</th>
|
|
<th>{{ sort_header('created_at', 'Created') }}</th>
|
|
<th>Review</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{% for item in items %}
|
|
<tr class="item-row">
|
|
<!-- Type Badge -->
|
|
<td class="col-type">
|
|
<span class="badge badge-{{ item.item_type }}">
|
|
{% if item.item_type == 'post' %}
|
|
Post
|
|
{% elif item.item_type == 'reply' %}
|
|
Reply
|
|
{% elif item.item_type == 'mention' %}
|
|
Mention
|
|
{% endif %}
|
|
</span>
|
|
</td>
|
|
|
|
<!-- Author -->
|
|
<td class="col-author">
|
|
{% if item.author_handle %}
|
|
<a href="https://{{ item.author_instance }}/@{{ item.author_username }}" target="_blank" rel="noopener" class="author-link">
|
|
{{ item.author_handle }}
|
|
</a>
|
|
{% endif %}
|
|
</td>
|
|
|
|
<!-- Content Text -->
|
|
<td class="col-text">
|
|
{% if item.url %}
|
|
<a href="{{ item.url }}" target="_blank" rel="noopener" class="content-link">
|
|
{{ item.text | truncate_text(200) }}
|
|
</a>
|
|
{% else %}
|
|
<span class="content-text">{{ item.text | truncate_text(200) }}</span>
|
|
{% endif %}
|
|
</td>
|
|
|
|
<!-- Score with Bar -->
|
|
<td class="col-score">
|
|
<div class="score-bar-container">
|
|
{% set score_pct = (item.overall * 100) | int %}
|
|
{% if item.overall < 0.3 %}
|
|
{% set bar_class = 'score-bar-low' %}
|
|
{% elif item.overall < 0.6 %}
|
|
{% set bar_class = 'score-bar-medium' %}
|
|
{% else %}
|
|
{% set bar_class = 'score-bar-high' %}
|
|
{% endif %}
|
|
<div class="score-bar {{ bar_class }}" style="width: {{ score_pct }}%"></div>
|
|
<span class="score-number">{{ "%.2f" | format(item.overall) }}</span>
|
|
</div>
|
|
</td>
|
|
|
|
<!-- Top Category -->
|
|
<td class="col-category">
|
|
{% if item.top_category %}
|
|
<span class="badge badge-category">{{ item.top_category }}</span>
|
|
{% else %}
|
|
<span class="text-muted">—</span>
|
|
{% endif %}
|
|
</td>
|
|
|
|
<!-- Created Time -->
|
|
<td class="col-created">
|
|
<span class="time-ago" title="{{ item.created_at }}">
|
|
{{ item.created_at | time_ago }}
|
|
</span>
|
|
</td>
|
|
|
|
<!-- Review Buttons -->
|
|
<td class="col-review">
|
|
<div class="review-buttons" data-item-id="{{ item.item_id }}" data-source-type="{{ item.source_type }}" data-current-status="{{ item.review_status or '' }}">
|
|
<button class="btn-review btn-correct {% if item.review_status == 'correct' %}active{% endif %}" data-status="correct" title="Mark as correctly flagged">✓</button>
|
|
<button class="btn-review btn-incorrect {% if item.review_status == 'incorrect' %}active{% endif %}" data-status="incorrect" title="Mark as incorrectly flagged">✗</button>
|
|
<button class="btn-review btn-unsure {% if item.review_status == 'unsure' %}active{% endif %}" data-status="unsure" title="Mark as unsure">?</button>
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{% endfor %}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<!-- Pagination -->
|
|
{% if total_pages > 1 %}
|
|
<div class="pagination">
|
|
{% if page > 1 %}
|
|
<a href="{{ url_for('analysis_flagged', page=1, content_type=content_type, category=category, account_did=account_did, threshold=threshold, review_status=review_status, date_from=date_from, date_to=date_to, sort=sort, dir=direction) }}" class="btn-pagination">First</a>
|
|
<a href="{{ url_for('analysis_flagged', page=page-1, content_type=content_type, category=category, account_did=account_did, threshold=threshold, review_status=review_status, date_from=date_from, date_to=date_to, sort=sort, dir=direction) }}" class="btn-pagination">Previous</a>
|
|
{% endif %}
|
|
|
|
<span class="pagination-info">Page {{ page }} of {{ total_pages }}</span>
|
|
|
|
{% if page < total_pages %}
|
|
<a href="{{ url_for('analysis_flagged', page=page+1, content_type=content_type, category=category, account_did=account_did, threshold=threshold, review_status=review_status, date_from=date_from, date_to=date_to, sort=sort, dir=direction) }}" class="btn-pagination">Next</a>
|
|
<a href="{{ url_for('analysis_flagged', page=total_pages, content_type=content_type, category=category, account_did=account_did, threshold=threshold, review_status=review_status, date_from=date_from, date_to=date_to, sort=sort, dir=direction) }}" class="btn-pagination">Last</a>
|
|
{% endif %}
|
|
</div>
|
|
{% endif %}
|
|
|
|
{% else %}
|
|
<!-- Empty State -->
|
|
<div class="empty-state">
|
|
<p class="empty-icon">∅</p>
|
|
<p class="empty-text">No flagged content found</p>
|
|
<p class="empty-subtext">Try adjusting your filters or threshold</p>
|
|
</div>
|
|
{% endif %}
|
|
</div>
|
|
{% endblock %}
|
|
|
|
{% block extra_css %}
|
|
<style>
|
|
:root {
|
|
--dark-bg: #1a1a2e;
|
|
--dark-card: #16213e;
|
|
--dark-nav: #0f3460;
|
|
--dark-text: #e0e0e0;
|
|
--accent-primary: #00b4d8;
|
|
--badge-post: #00b4d8;
|
|
--badge-reply: #9b59b6;
|
|
--badge-mention: #2ecc71;
|
|
--tox-low: #2ecc71;
|
|
--tox-medium: #f39c12;
|
|
--tox-high: #e74c3c;
|
|
}
|
|
|
|
.flagged-container {
|
|
padding: 2rem;
|
|
max-width: 1400px;
|
|
margin: 0 auto;
|
|
}
|
|
|
|
/* Page Header */
|
|
.page-header {
|
|
display: flex;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.page-header h1 {
|
|
font-size: 2rem;
|
|
font-weight: 700;
|
|
color: var(--dark-text);
|
|
margin: 0;
|
|
}
|
|
|
|
.total-badge {
|
|
background: var(--accent-primary);
|
|
color: var(--dark-bg);
|
|
font-weight: 600;
|
|
padding: 0.5rem 1rem;
|
|
border-radius: 2rem;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
/* Filter Bar */
|
|
.filter-bar {
|
|
background: var(--dark-card);
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
border-radius: 0.5rem;
|
|
padding: 1.5rem;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
.filter-form {
|
|
display: flex;
|
|
flex-wrap: wrap;
|
|
gap: 1rem;
|
|
align-items: flex-end;
|
|
}
|
|
|
|
.filter-group {
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: 0.5rem;
|
|
flex: 1;
|
|
min-width: 150px;
|
|
}
|
|
|
|
.filter-group label {
|
|
font-size: 0.9rem;
|
|
font-weight: 600;
|
|
color: var(--dark-text);
|
|
}
|
|
|
|
.filter-select,
|
|
.filter-input {
|
|
background: var(--dark-bg);
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
border-radius: 0.375rem;
|
|
color: var(--dark-text);
|
|
padding: 0.625rem;
|
|
font-size: 0.9rem;
|
|
font-family: inherit;
|
|
}
|
|
|
|
.filter-select:hover,
|
|
.filter-input:hover {
|
|
border-color: rgba(255, 255, 255, 0.3);
|
|
}
|
|
|
|
.filter-select:focus,
|
|
.filter-input:focus {
|
|
outline: none;
|
|
border-color: var(--accent-primary);
|
|
background: var(--dark-bg);
|
|
color: var(--dark-text);
|
|
}
|
|
|
|
.btn-apply {
|
|
background: var(--accent-primary);
|
|
color: var(--dark-bg);
|
|
border: none;
|
|
border-radius: 0.375rem;
|
|
padding: 0.625rem 1.25rem;
|
|
font-weight: 600;
|
|
cursor: pointer;
|
|
font-size: 0.9rem;
|
|
transition: all 0.2s ease;
|
|
}
|
|
|
|
.btn-apply:hover {
|
|
opacity: 0.9;
|
|
transform: translateY(-1px);
|
|
}
|
|
|
|
.btn-apply:active {
|
|
transform: translateY(0);
|
|
}
|
|
|
|
/* Table Wrapper */
|
|
.table-wrapper {
|
|
background: var(--dark-card);
|
|
border: 1px solid rgba(255, 255, 255, 0.1);
|
|
border-radius: 0.5rem;
|
|
overflow-x: auto;
|
|
margin-bottom: 2rem;
|
|
}
|
|
|
|
/* Table Styles */
|
|
.flagged-table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 0.9rem;
|
|
}
|
|
|
|
.flagged-table thead {
|
|
background: rgba(0, 0, 0, 0.3);
|
|
border-bottom: 2px solid rgba(255, 255, 255, 0.1);
|
|
}
|
|
|
|
.flagged-table th {
|
|
padding: 1rem;
|
|
text-align: left;
|
|
font-weight: 600;
|
|
color: var(--dark-text);
|
|
white-space: nowrap;
|
|
}
|
|
|
|
/* Sort Links */
|
|
.sort-link {
|
|
color: var(--dark-text);
|
|
text-decoration: none;
|
|
display: inline-flex;
|
|
align-items: center;
|
|
gap: 0.25rem;
|
|
transition: color 0.2s ease;
|
|
}
|
|
|
|
.sort-link:hover {
|
|
color: var(--accent-primary);
|
|
}
|
|
|
|
.sort-icon {
|
|
font-size: 0.8rem;
|
|
opacity: 0.7;
|
|
}
|
|
|
|
.flagged-table td {
|
|
padding: 1rem;
|
|
border-bottom: 1px solid rgba(255, 255, 255, 0.05);
|
|
color: var(--dark-text);
|
|
}
|
|
|
|
.flagged-table tbody tr:hover {
|
|
background: rgba(0, 180, 216, 0.05);
|
|
}
|
|
|
|
/* Column Styles */
|
|
.col-type {
|
|
width: 90px;
|
|
}
|
|
|
|
.col-author {
|
|
width: 200px;
|
|
}
|
|
|
|
.col-text {
|
|
min-width: 300px;
|
|
}
|
|
|
|
.col-score {
|
|
width: 150px;
|
|
}
|
|
|
|
.col-category {
|
|
width: 140px;
|
|
}
|
|
|
|
.col-created {
|
|
width: 120px;
|
|
}
|
|
|
|
.col-review {
|
|
width: 130px;
|
|
}
|
|
|
|
/* Badges */
|
|
.badge {
|
|
display: inline-block;
|
|
padding: 0.35rem 0.75rem;
|
|
border-radius: 0.25rem;
|
|
font-size: 0.8rem;
|
|
font-weight: 600;
|
|
text-transform: uppercase;
|
|
letter-spacing: 0.5px;
|
|
}
|
|
|
|
.badge-post {
|
|
background: rgba(0, 180, 216, 0.2);
|
|
color: var(--badge-post);
|
|
}
|
|
|
|
.badge-reply {
|
|
background: rgba(155, 89, 182, 0.2);
|
|
color: var(--badge-reply);
|
|
}
|
|
|
|
.badge-mention {
|
|
background: rgba(46, 204, 113, 0.2);
|
|
color: var(--badge-mention);
|
|
}
|
|
|
|
.badge-category {
|
|
background: rgba(0, 180, 216, 0.15);
|
|
color: var(--accent-primary);
|
|
}
|
|
|
|
/* Author Links */
|
|
.author-link {
|
|
color: var(--accent-primary);
|
|
text-decoration: none;
|
|
transition: color 0.2s ease;
|
|
}
|
|
|
|
.author-link:hover {
|
|
color: rgba(0, 180, 216, 0.8);
|
|
text-decoration: underline;
|
|
}
|
|
|
|
.mention-arrow {
|
|
color: rgba(255, 255, 255, 0.3);
|
|
margin: 0 0.5rem;
|
|
}
|
|
|
|
/* Content Link */
|
|
.content-link {
|
|
color: var(--dark-text);
|
|
text-decoration: none;
|
|
transition: color 0.2s ease;
|
|
}
|
|
|
|
.content-link:hover {
|
|
color: var(--accent-primary);
|
|
}
|
|
|
|
.content-text {
|
|
color: rgba(255, 255, 255, 0.7);
|
|
}
|
|
|
|
/* Score Bar */
|
|
.score-bar-container {
|
|
position: relative;
|
|
height: 30px;
|
|
background: rgba(255, 255, 255, 0.05);
|
|
border-radius: 0.25rem;
|
|
overflow: hidden;
|
|
display: flex;
|
|
align-items: center;
|
|
padding: 0 0.5rem;
|
|
}
|
|
|
|
.score-bar {
|
|
position: absolute;
|
|
height: 100%;
|
|
left: 0;
|
|
top: 0;
|
|
transition: width 0.3s ease;
|
|
}
|
|
|
|
.score-bar-low {
|
|
background: linear-gradient(90deg, rgba(46, 204, 113, 0.3), rgba(46, 204, 113, 0.5));
|
|
}
|
|
|
|
.score-bar-medium {
|
|
background: linear-gradient(90deg, rgba(243, 156, 18, 0.3), rgba(243, 156, 18, 0.5));
|
|
}
|
|
|
|
.score-bar-high {
|
|
background: linear-gradient(90deg, rgba(231, 76, 60, 0.3), rgba(231, 76, 60, 0.5));
|
|
}
|
|
|
|
.score-number {
|
|
position: relative;
|
|
z-index: 1;
|
|
font-weight: 600;
|
|
color: var(--dark-text);
|
|
font-size: 0.85rem;
|
|
}
|
|
|
|
/* Time Ago */
|
|
.time-ago {
|
|
color: rgba(255, 255, 255, 0.6);
|
|
font-size: 0.85rem;
|
|
cursor: help;
|
|
}
|
|
|
|
.time-ago:hover {
|
|
color: var(--dark-text);
|
|
}
|
|
|
|
.text-muted {
|
|
color: rgba(255, 255, 255, 0.3);
|
|
}
|
|
|
|
/* Review Buttons */
|
|
.review-buttons {
|
|
display: flex;
|
|
gap: 0.25rem;
|
|
justify-content: center;
|
|
}
|
|
|
|
.btn-review {
|
|
background: var(--dark-bg);
|
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
|
color: var(--dark-text);
|
|
width: 32px;
|
|
height: 32px;
|
|
border-radius: 0.25rem;
|
|
font-size: 1rem;
|
|
cursor: pointer;
|
|
transition: all 0.2s ease;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.btn-review:hover {
|
|
transform: translateY(-2px);
|
|
border-color: rgba(255, 255, 255, 0.4);
|
|
}
|
|
|
|
.btn-correct:hover, .btn-correct.active {
|
|
background: var(--tox-low);
|
|
border-color: var(--tox-low);
|
|
color: var(--dark-bg);
|
|
}
|
|
|
|
.btn-incorrect:hover, .btn-incorrect.active {
|
|
background: var(--tox-high);
|
|
border-color: var(--tox-high);
|
|
color: var(--dark-bg);
|
|
}
|
|
|
|
.btn-unsure:hover, .btn-unsure.active {
|
|
background: var(--tox-medium);
|
|
border-color: var(--tox-medium);
|
|
color: var(--dark-bg);
|
|
}
|
|
|
|
.btn-review.active {
|
|
font-weight: 700;
|
|
transform: none;
|
|
}
|
|
|
|
.btn-review.active:hover {
|
|
opacity: 0.8;
|
|
}
|
|
|
|
/* Empty State */
|
|
.empty-state {
|
|
text-align: center;
|
|
padding: 4rem 2rem;
|
|
background: var(--dark-card);
|
|
border: 2px dashed rgba(255, 255, 255, 0.2);
|
|
border-radius: 0.5rem;
|
|
}
|
|
|
|
.empty-icon {
|
|
font-size: 3rem;
|
|
color: rgba(255, 255, 255, 0.2);
|
|
margin: 0 0 1rem 0;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 1.2rem;
|
|
font-weight: 600;
|
|
color: var(--dark-text);
|
|
margin: 0 0 0.5rem 0;
|
|
}
|
|
|
|
.empty-subtext {
|
|
color: rgba(255, 255, 255, 0.5);
|
|
margin: 0;
|
|
}
|
|
|
|
/* Pagination */
|
|
.pagination {
|
|
display: flex;
|
|
justify-content: center;
|
|
align-items: center;
|
|
gap: 1rem;
|
|
margin-top: 2rem;
|
|
}
|
|
|
|
.pagination-info {
|
|
color: var(--dark-text);
|
|
font-weight: 500;
|
|
min-width: 150px;
|
|
text-align: center;
|
|
}
|
|
|
|
.btn-pagination {
|
|
background: var(--dark-card);
|
|
color: var(--accent-primary);
|
|
border: 1px solid var(--accent-primary);
|
|
padding: 0.5rem 1rem;
|
|
border-radius: 0.375rem;
|
|
text-decoration: none;
|
|
font-weight: 600;
|
|
font-size: 0.9rem;
|
|
transition: all 0.2s ease;
|
|
cursor: pointer;
|
|
}
|
|
|
|
.btn-pagination:hover {
|
|
background: var(--accent-primary);
|
|
color: var(--dark-bg);
|
|
}
|
|
|
|
.btn-pagination:active {
|
|
transform: scale(0.98);
|
|
}
|
|
|
|
/* Responsive */
|
|
@media (max-width: 1024px) {
|
|
.filter-form {
|
|
flex-direction: column;
|
|
}
|
|
|
|
.filter-group {
|
|
width: 100%;
|
|
}
|
|
|
|
.col-text {
|
|
min-width: 250px;
|
|
}
|
|
}
|
|
|
|
@media (max-width: 768px) {
|
|
.flagged-container {
|
|
padding: 1rem;
|
|
}
|
|
|
|
.page-header {
|
|
flex-direction: column;
|
|
align-items: flex-start;
|
|
}
|
|
|
|
.page-header h1 {
|
|
font-size: 1.5rem;
|
|
}
|
|
|
|
.table-wrapper {
|
|
font-size: 0.8rem;
|
|
}
|
|
|
|
.flagged-table th,
|
|
.flagged-table td {
|
|
padding: 0.75rem 0.5rem;
|
|
}
|
|
|
|
.col-author,
|
|
.col-text {
|
|
min-width: 180px;
|
|
}
|
|
|
|
.col-created {
|
|
width: 100px;
|
|
}
|
|
}
|
|
</style>
|
|
{% endblock %}
|
|
|
|
{% block extra_js %}
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
// Handle review button clicks
|
|
document.querySelectorAll('.btn-review').forEach(button => {
|
|
button.addEventListener('click', async function() {
|
|
const buttonContainer = this.parentElement;
|
|
const itemId = buttonContainer.dataset.itemId;
|
|
const sourceType = buttonContainer.dataset.sourceType;
|
|
const currentStatus = buttonContainer.dataset.currentStatus;
|
|
const clickedStatus = this.dataset.status;
|
|
|
|
// If clicking the same status, do nothing (it's already set)
|
|
if (currentStatus === clickedStatus) {
|
|
return;
|
|
}
|
|
|
|
// Disable all buttons while processing
|
|
buttonContainer.querySelectorAll('.btn-review').forEach(btn => btn.disabled = true);
|
|
|
|
try {
|
|
const response = await fetch('/api/review/submit', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
item_id: itemId,
|
|
source_type: sourceType,
|
|
review_status: clickedStatus,
|
|
}),
|
|
});
|
|
|
|
if (response.ok) {
|
|
// Update current status
|
|
buttonContainer.dataset.currentStatus = clickedStatus;
|
|
|
|
// Remove active class from all buttons
|
|
buttonContainer.querySelectorAll('.btn-review').forEach(btn => {
|
|
btn.classList.remove('active');
|
|
});
|
|
|
|
// Add active class to clicked button
|
|
this.classList.add('active');
|
|
|
|
// Re-enable all buttons
|
|
buttonContainer.querySelectorAll('.btn-review').forEach(btn => btn.disabled = false);
|
|
} else {
|
|
// Re-enable buttons on error
|
|
buttonContainer.querySelectorAll('.btn-review').forEach(btn => btn.disabled = false);
|
|
alert('Failed to submit review. Please try again.');
|
|
}
|
|
} catch (error) {
|
|
// Re-enable buttons on error
|
|
buttonContainer.querySelectorAll('.btn-review').forEach(btn => btn.disabled = false);
|
|
console.error('Error submitting review:', error);
|
|
alert('Failed to submit review. Please try again.');
|
|
}
|
|
});
|
|
});
|
|
});
|
|
</script>
|
|
{% endblock %}
|