Files
thrillwiki_django_no_react/templates/moderation/partials/dashboard_content.html
2025-09-21 20:19:12 -04:00

223 lines
12 KiB
HTML

{% load static %}
<h1 class="mb-6 text-2xl font-bold text-gray-900 dark:text-gray-200">Moderation Dashboard</h1>
<div class="space-y-6">
<div class="flex items-center justify-between p-4 bg-white border rounded-lg dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50">
<div class="flex items-center space-x-4">
<a href="{% url 'moderation:submission_list' %}?status=PENDING"
class="flex items-center px-4 py-2.5 rounded-lg font-medium transition-all duration-200 {% if request.GET.status == 'PENDING' or not request.GET.status %}bg-blue-100 text-blue-900 dark:bg-blue-900/40 dark:text-blue-400{% else %}text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-300{% endif %}"
hx-get="{% url 'moderation:submission_list' %}?status=PENDING"
hx-target="#dashboard-content"
hx-push-url="true"
hx-indicator="#loading-indicator">
<i class="mr-2.5 text-lg fas fa-clock"></i>
<span>Pending</span>
</a>
<a href="{% url 'moderation:submission_list' %}?status=APPROVED"
class="flex items-center px-4 py-2.5 rounded-lg font-medium transition-all duration-200 {% if request.GET.status == 'APPROVED' %}bg-blue-100 text-blue-900 dark:bg-blue-900/40 dark:text-blue-400{% else %}text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-300{% endif %}"
hx-get="{% url 'moderation:submission_list' %}?status=APPROVED"
hx-target="#dashboard-content"
hx-push-url="true"
hx-indicator="#loading-indicator">
<i class="mr-2.5 text-lg fas fa-check"></i>
<span>Approved</span>
</a>
<a href="{% url 'moderation:submission_list' %}?status=REJECTED"
class="flex items-center px-4 py-2.5 rounded-lg font-medium transition-all duration-200 {% if request.GET.status == 'REJECTED' %}bg-blue-100 text-blue-900 dark:bg-blue-900/40 dark:text-blue-400{% else %}text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-300{% endif %}"
hx-get="{% url 'moderation:submission_list' %}?status=REJECTED"
hx-target="#dashboard-content"
hx-push-url="true"
hx-indicator="#loading-indicator">
<i class="mr-2.5 text-lg fas fa-times"></i>
<span>Rejected</span>
</a>
<a href="{% url 'moderation:submission_list' %}?status=ESCALATED"
class="flex items-center px-4 py-2.5 rounded-lg font-medium transition-all duration-200 {% if request.GET.status == 'ESCALATED' %}bg-blue-100 text-blue-900 dark:bg-blue-900/40 dark:text-blue-400{% else %}text-gray-600 dark:text-gray-400 hover:text-gray-900 dark:hover:text-gray-300{% endif %}"
hx-get="{% url 'moderation:submission_list' %}?status=ESCALATED"
hx-target="#dashboard-content"
hx-push-url="true"
hx-indicator="#loading-indicator">
<i class="mr-2.5 text-lg fas fa-exclamation-triangle"></i>
<span>Escalated</span>
</a>
</div>
<button class="flex items-center px-4 py-2.5 rounded-lg font-medium transition-all duration-200 text-gray-600 dark:text-gray-400 hover:text-blue-900 hover:bg-blue-100 dark:hover:text-blue-400 dark:hover:bg-blue-900/40"
hx-get="{{ request.get_full_path }}"
hx-target="#dashboard-content"
hx-indicator="#loading-indicator">
<i class="mr-2.5 text-lg fas fa-sync-alt"></i>
<span>Refresh</span>
</button>
</div>
<div class="p-6 bg-white border rounded-lg dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50">
<form class="mb-6"
x-data="{ showFilters: false }"
hx-get="{% url 'moderation:submission_list' %}"
hx-target="#dashboard-content"
hx-trigger="change from:select"
hx-push-url="true"
aria-label="Submission filters">
<!-- Mobile Filter Toggle -->
<button type="button"
class="flex items-center w-full gap-2 p-3 mb-4 font-medium text-left text-gray-700 transition-colors duration-200 bg-gray-100 rounded-lg md:hidden dark:text-gray-300 dark:bg-gray-900"
@click="showFilters = !showFilters"
:aria-expanded="showFilters"
aria-controls="filter-controls">
<i class="fas" :class="showFilters ? 'fa-chevron-up' : 'fa-chevron-down'"></i>
<span>Filter Options</span>
<span class="flex items-center ml-auto space-x-1 text-sm text-gray-500 dark:text-gray-400">
<span class="active-filters">{{ request.GET|length }} active</span>
</span>
</button>
<!-- Filter Controls -->
<div id="filter-controls"
class="grid gap-4 transition-all duration-200 md:grid-cols-3"
:class="{'hidden md:grid': !showFilters, 'grid': showFilters}"
role="group"
aria-label="Filter controls">
<div class="relative">
<label id="submission-type-label"
class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">
Submission Type
</label>
<select name="submission_type"
aria-labelledby="submission-type-label"
class="w-full px-3 py-2 text-gray-900 bg-white border rounded-lg dark:text-gray-300 dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50 focus:outline-hidden focus:ring-2 focus:ring-blue-500"
@change="$dispatch('filter-changed')">
<option value="">All Submissions</option>
<option value="text" {% if request.GET.submission_type == 'text' %}selected{% endif %}>Text Submissions</option>
<option value="photo" {% if request.GET.submission_type == 'photo' %}selected{% endif %}>Photo Submissions</option>
</select>
</div>
<div class="relative">
<label id="type-label"
class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">
Type
</label>
<select name="type"
aria-labelledby="type-label"
class="w-full px-3 py-2 text-gray-900 bg-white border rounded-lg dark:text-gray-300 dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50 focus:outline-hidden focus:ring-2 focus:ring-blue-500"
@change="$dispatch('filter-changed')">
<option value="">All Types</option>
<option value="CREATE" {% if request.GET.type == 'CREATE' %}selected{% endif %}>New Submissions</option>
<option value="EDIT" {% if request.GET.type == 'EDIT' %}selected{% endif %}>Edit Submissions</option>
</select>
</div>
<div class="relative">
<label id="content-type-label"
class="block mb-2 text-sm font-medium text-gray-600 dark:text-gray-400">
Content Type
</label>
<select name="content_type"
aria-labelledby="content-type-label"
class="w-full px-3 py-2 text-gray-900 bg-white border rounded-lg dark:text-gray-300 dark:bg-gray-800 border-gray-200/50 dark:border-gray-700/50 focus:outline-hidden focus:ring-2 focus:ring-blue-500"
@change="$dispatch('filter-changed')">
<option value="">All Content</option>
<option value="park" {% if request.GET.content_type == 'park' %}selected{% endif %}>Parks</option>
<option value="ride" {% if request.GET.content_type == 'ride' %}selected{% endif %}>Rides</option>
<option value="company" {% if request.GET.content_type == 'company' %}selected{% endif %}>Companies</option>
</select>
</div>
<!-- Applied Filters Summary -->
<div class="hidden pt-2 md:col-span-3 md:block">
<div class="flex flex-wrap gap-2"
x-show="$store.filters.hasActiveFilters"
x-cloak>
<template x-for="filter in $store.filters.active" :key="filter.name">
<span class="inline-flex items-center px-2 py-1 text-sm bg-blue-100 rounded dark:bg-blue-900/40">
<span class="mr-1 text-blue-700 dark:text-blue-300" x-text="filter.label + ':'"></span>
<span class="font-medium text-blue-900 dark:text-blue-100" x-text="filter.value"></span>
</span>
</template>
</div>
</div>
</div>
</form>
<div class="space-y-4">
{% include "moderation/partials/submission_list.html" with submissions=submissions user=user %}
</div>
</div>
</div>
<div id="toast-container"
x-data="{
show: false,
message: '',
icon: 'check',
color: 'green',
showToast(msg, icn = 'check', clr = 'green') {
this.message = msg;
this.icon = icn;
this.color = clr;
this.show = true;
setTimeout(() => this.show = false, 3000);
}
}"
@submission-approved.window="showToast('Submission approved successfully', 'check', 'green')"
@submission-rejected.window="showToast('Submission rejected', 'times', 'red')"
@submission-escalated.window="showToast('Submission escalated', 'exclamation-triangle', 'yellow')"
@submission-updated.window="showToast('Changes saved successfully', 'check', 'blue')"
class="fixed z-50 bottom-4 right-4">
<div x-show="show"
x-transition:enter="ease-out duration-300"
x-transition:enter-start="opacity-0 translate-y-full"
x-transition:enter-end="opacity-100 translate-y-0"
x-transition:leave="ease-in duration-200"
x-transition:leave-start="opacity-100 translate-y-0"
x-transition:leave-end="opacity-0 translate-y-full"
class="flex items-center w-full max-w-xs p-4 text-gray-400 bg-gray-800 rounded-lg shadow">
<div class="inline-flex items-center justify-center shrink-0 w-8 h-8 rounded-lg"
:class="{
'text-green-400 bg-green-900/40': color === 'green',
'text-red-400 bg-red-900/40': color === 'red',
'text-yellow-400 bg-yellow-900/40': color === 'yellow',
'text-blue-400 bg-blue-900/40': color === 'blue'
}">
<i class="fas" :class="'fa-' + icon"></i>
</div>
<div class="ml-3 text-sm font-normal" x-text="message"></div>
<button type="button"
class="ml-auto -mx-1.5 -my-1.5 text-gray-400 hover:text-gray-300 rounded-lg p-1.5 inline-flex h-8 w-8"
@click="show = false">
<i class="fas fa-times"></i>
</button>
</div>
</div>
<script>
document.body.addEventListener('htmx:afterRequest', function(evt) {
if (evt.detail.successful) {
const path = evt.detail.requestConfig.path;
let event;
if (path.includes('approve')) {
event = new CustomEvent('submission-approved');
} else if (path.includes('reject')) {
event = new CustomEvent('submission-rejected');
} else if (path.includes('escalate')) {
event = new CustomEvent('submission-escalated');
} else if (path.includes('edit')) {
event = new CustomEvent('submission-updated');
}
if (event) {
window.dispatchEvent(event);
}
}
});
</script>