Add release report response

This commit is contained in:
DariusIII
2026-06-08 16:31:15 +02:00
parent 4bb4358063
commit f8294f1b0a
13 changed files with 385 additions and 13 deletions
@@ -113,6 +113,10 @@ Alpine.data('adminReleaseReports', () => ({
revertModalOpen: false,
revertActionUrl: '',
revertStatus: '',
responseModalOpen: false,
responseActionUrl: '',
responseContent: '',
responseIsPublic: true,
allChecked: false,
selectedCount: 0,
rootEl: null,
@@ -144,6 +148,24 @@ Alpine.data('adminReleaseReports', () => ({
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;
},
@@ -111,6 +111,7 @@
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Release</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Reporter</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Reason</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Response</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Status</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Date</th>
<th class="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Actions</th>
@@ -176,6 +177,24 @@
</button>
@endif
</td>
<td class="px-4 py-4">
@if($report->response)
<div class="max-w-xs space-y-1">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium {{ $report->response_is_public ? 'bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200' : 'bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200' }}">
<i class="fas fa-reply mr-1"></i>
{{ $report->response_is_public ? 'Public response' : 'Private note' }}
</span>
<p class="text-xs text-gray-700 dark:text-gray-300 break-words">{{ Str::limit($report->response, 90) }}</p>
@if($report->responder && $report->responded_at)
<div class="text-xs text-gray-500 dark:text-gray-400">
by {{ $report->responder->username }} at {{ $report->responded_at->format('M d, Y H:i') }}
</div>
@endif
</div>
@else
<span class="text-xs text-gray-500 dark:text-gray-400">No response</span>
@endif
</td>
<td class="px-4 py-4 whitespace-nowrap">
@php
$statusColors = [
@@ -280,11 +299,27 @@
title="Revert to Reviewed for further action">
<i class="fas fa-undo mr-1"></i> Revert
</button>
<span class="text-xs text-gray-500 dark:text-gray-400">{{ ucfirst($report->status) }}</span>
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium {{ $statusColors[$report->status] ?? 'bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200' }}">
<i class="fas {{ $statusIcons[$report->status] ?? 'fa-question' }} mr-1"></i>
{{ ucfirst($report->status) }}
</span>
@else
<span class="text-xs text-gray-500 dark:text-gray-400">{{ ucfirst($report->status) }}</span>
<span class="inline-flex items-center px-2.5 py-1 rounded-full text-xs font-medium {{ $statusColors[$report->status] ?? 'bg-gray-100 dark:bg-gray-700 text-gray-800 dark:text-gray-200' }}">
<i class="fas {{ $statusIcons[$report->status] ?? 'fa-question' }} mr-1"></i>
{{ ucfirst($report->status) }}
</span>
@endif
<button type="button"
class="response-report-btn px-3 py-1.5 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 transition text-sm inline-flex items-center"
data-action-url="{{ route('admin.release-reports.update-response', $report->id) }}"
data-response="{{ e($report->response ?? '') }}"
data-public="{{ $report->response_is_public ? '1' : '0' }}"
@click="showResponse($event.currentTarget.dataset.actionUrl, $event.currentTarget.dataset.response, $event.currentTarget.dataset.public === '1')"
title="{{ $report->response ? 'Edit response' : 'Add response' }}">
<i class="fas fa-reply mr-1"></i> {{ $report->response ? 'Edit Response' : 'Add Response' }}
</button>
@if($report->release)
<a href="{{ url('/details/' . $report->release->guid) }}"
target="_blank"
@@ -371,6 +406,75 @@
</div>
</div>
<!-- Report Response Modal -->
<div id="reportResponseModal"
x-cloak
x-show="responseModalOpen"
@keydown.escape.window="closeResponse()"
class="fixed inset-0 z-50 overflow-y-auto">
<!-- Backdrop -->
<div class="response-modal-backdrop fixed inset-0 transition-opacity bg-gray-500/75 dark:bg-gray-900/75"
@click="closeResponse()"></div>
<!-- Modal panel container -->
<div class="fixed inset-0 z-10 overflow-y-auto" @click.self="closeResponse()">
<div class="flex min-h-full items-center justify-center p-4 text-center sm:p-0">
<!-- Modal Content -->
<div class="relative w-full max-w-2xl p-6 overflow-hidden text-left align-middle transition-all transform bg-white dark:bg-gray-800 shadow-xl rounded-lg">
<div class="flex items-center justify-between mb-4">
<h3 class="text-lg font-semibold text-gray-900 dark:text-gray-100">
<i class="fas fa-reply text-indigo-500 mr-2"></i>Staff Response
</h3>
<button type="button" class="response-modal-close text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" @click="closeResponse()">
<i class="fas fa-times"></i>
</button>
</div>
<form id="reportResponseForm" x-ref="responseForm" method="POST" action="" @submit.prevent="submitResponse()">
@csrf
<div class="space-y-4">
<div>
<label for="reportResponseText" class="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1">Response</label>
<textarea id="reportResponseText"
name="response"
rows="7"
maxlength="2000"
x-model="responseContent"
class="w-full rounded-lg border-gray-300 dark:border-gray-600 dark:bg-gray-900 dark:text-gray-100 focus:border-indigo-500 focus:ring-indigo-500"
placeholder="Write the staff response shown on the release details page..."></textarea>
<div class="mt-1 flex justify-between text-xs text-gray-500 dark:text-gray-400">
<span>Leave blank and save to clear the response.</span>
<span><span x-text="responseCharCount()"></span>/2000</span>
</div>
</div>
<label class="flex items-start gap-2 text-sm text-gray-700 dark:text-gray-300">
<input type="hidden" name="response_is_public" value="0">
<input type="checkbox"
name="response_is_public"
value="1"
x-model="responseIsPublic"
class="mt-1 rounded border-gray-300 dark:border-gray-600 text-indigo-600 focus:ring-indigo-500 dark:bg-gray-700">
<span>
Show this response publicly on release details pages and enable the response badge on browse/search results.
</span>
</label>
</div>
<div class="mt-6 flex justify-end gap-3">
<button type="button" class="response-modal-close px-4 py-2 text-sm font-medium text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 rounded-lg hover:bg-gray-200 dark:hover:bg-gray-600 transition" @click="closeResponse()">
Cancel
</button>
<button type="submit" class="px-4 py-2 text-sm font-medium text-white bg-indigo-600 rounded-lg hover:bg-indigo-700 transition">
<i class="fas fa-save mr-1"></i> Save Response
</button>
</div>
</form>
</div>
</div>
</div>
</div>
<!-- Revert Confirmation Modal -->
<div id="revertConfirmModal"
x-cloak
+20
View File
@@ -142,6 +142,12 @@
<i class="fas fa-flag mr-1"></i> Reported ({{ $result->report_count }})
</span>
@endif
@if(!empty($result->report_response_count) && $result->report_response_count > 0)
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200"
title="Staff response available on release details">
<i class="fas fa-reply mr-1"></i> Response
</span>
@endif
@if(!empty($result->failed_count) && $result->failed_count > 0)
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-red-100 dark:bg-red-900 text-red-800 dark:text-red-200"
title="{{ $result->failed_count }} user(s) reported download failure">
@@ -283,6 +289,20 @@
<a href="{{ url('/details/' . $result->guid) }}" class="text-primary-600 dark:text-primary-400 hover:text-primary-800 dark:hover:text-primary-300 font-medium wrap-break-word text-base">
{{ $result->searchname }}
</a>
<div class="flex flex-wrap items-center gap-2 mt-2">
@if(!empty($result->report_count) && $result->report_count > 0)
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-orange-100 dark:bg-orange-900 text-orange-800 dark:text-orange-200"
title="Reported: {{ \App\Models\ReleaseReport::reasonKeysToLabels($result->report_reasons ?? '') }}">
<i class="fas fa-flag mr-1"></i> Reported ({{ $result->report_count }})
</span>
@endif
@if(!empty($result->report_response_count) && $result->report_response_count > 0)
<span class="inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-blue-100 dark:bg-blue-900 text-blue-800 dark:text-blue-200"
title="Staff response available on release details">
<i class="fas fa-reply mr-1"></i> Response
</span>
@endif
</div>
<div class="flex flex-wrap items-center gap-2 mt-2 text-sm text-gray-600 dark:text-gray-400">
<span class="inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium bg-primary-100 dark:bg-primary-900/50 text-primary-800 dark:text-primary-200">
{{ $result->category_name ?? 'Other' }}
+20
View File
@@ -70,6 +70,26 @@
@endauth
<x-report-button :release-id="$release->id" variant="button-lg" />
</div>
@if(!empty($publicReportResponses) && $publicReportResponses->count() > 0)
<div class="mt-4 rounded-lg border border-blue-200 dark:border-blue-800 bg-blue-50 dark:bg-blue-900/20 p-4">
<h3 class="text-sm font-semibold text-blue-800 dark:text-blue-200 mb-3 flex items-center">
<i class="fas fa-reply mr-2"></i> Staff response
</h3>
<div class="space-y-3">
@foreach($publicReportResponses as $responseReport)
<div class="text-sm text-blue-900 dark:text-blue-100">
<div class="whitespace-pre-wrap break-words">{{ $responseReport->response }}</div>
<div class="mt-2 text-xs text-blue-700 dark:text-blue-300">
{{ $responseReport->responded_at ? 'Responded ' . $responseReport->responded_at->format('M d, Y H:i') : 'Staff response' }}
@if($responseReport->responder)
by {{ $responseReport->responder->username }}
@endif
</div>
</div>
@endforeach
</div>
</div>
@endif
</div>
</div>
</div>