feat(slides): add sort_order column, bulk delete, and reorder endpoints
Add sort_order to slides table with migration and model fillable. Add destroyBulk() for batch soft-delete by type/service_id and reorder() for drag-and-drop slide ordering. Auto-assign sort_order on image and zip uploads.
This commit is contained in:
parent
04d271f96a
commit
bef910b126
|
|
@ -76,6 +76,50 @@ public function destroy(Slide $slide): JsonResponse
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function destroyBulk(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$validated = $request->validate([
|
||||||
|
'type' => ['required', Rule::in(['information', 'moderation', 'sermon'])],
|
||||||
|
'service_id' => ['nullable', 'exists:services,id'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
$query = Slide::where('type', $validated['type']);
|
||||||
|
|
||||||
|
if ($validated['service_id']) {
|
||||||
|
$query->where('service_id', $validated['service_id']);
|
||||||
|
} else {
|
||||||
|
// Information slides without service_id (global)
|
||||||
|
$query->whereNull('service_id');
|
||||||
|
}
|
||||||
|
|
||||||
|
$count = $query->count();
|
||||||
|
$query->delete(); // soft-delete via SoftDeletes trait
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => $count.' Folien wurden gelöscht.',
|
||||||
|
'count' => $count,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function reorder(Request $request): JsonResponse
|
||||||
|
{
|
||||||
|
$validated = $request->validate([
|
||||||
|
'slides' => ['required', 'array', 'min:1'],
|
||||||
|
'slides.*.id' => ['required', 'integer', 'exists:slides,id'],
|
||||||
|
'slides.*.sort_order' => ['required', 'integer', 'min:0'],
|
||||||
|
]);
|
||||||
|
|
||||||
|
foreach ($validated['slides'] as $item) {
|
||||||
|
Slide::where('id', $item['id'])->update(['sort_order' => $item['sort_order']]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'success' => true,
|
||||||
|
'message' => 'Reihenfolge wurde aktualisiert.',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function updateExpireDate(Request $request, Slide $slide): JsonResponse
|
public function updateExpireDate(Request $request, Slide $slide): JsonResponse
|
||||||
{
|
{
|
||||||
if ($slide->type !== 'information') {
|
if ($slide->type !== 'information') {
|
||||||
|
|
@ -97,6 +141,13 @@ public function updateExpireDate(Request $request, Slide $slide): JsonResponse
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function nextSortOrder(string $type, ?int $serviceId): int
|
||||||
|
{
|
||||||
|
return (int) Slide::where('type', $type)
|
||||||
|
->when($serviceId, fn ($q) => $q->where('service_id', $serviceId), fn ($q) => $q->whereNull('service_id'))
|
||||||
|
->max('sort_order') + 1;
|
||||||
|
}
|
||||||
|
|
||||||
private function handleImage(
|
private function handleImage(
|
||||||
UploadedFile $file,
|
UploadedFile $file,
|
||||||
FileConversionService $conversionService,
|
FileConversionService $conversionService,
|
||||||
|
|
@ -117,6 +168,7 @@ private function handleImage(
|
||||||
'expire_date' => $expireDate,
|
'expire_date' => $expireDate,
|
||||||
'uploader_name' => $uploaderName,
|
'uploader_name' => $uploaderName,
|
||||||
'uploaded_at' => now(),
|
'uploaded_at' => now(),
|
||||||
|
'sort_order' => $this->nextSortOrder($type, $serviceId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return response()->json([
|
return response()->json([
|
||||||
|
|
@ -179,6 +231,8 @@ private function handleZip(
|
||||||
$results = $conversionService->processZip($file);
|
$results = $conversionService->processZip($file);
|
||||||
$slides = [];
|
$slides = [];
|
||||||
|
|
||||||
|
$sortOrder = $this->nextSortOrder($type, $serviceId);
|
||||||
|
|
||||||
foreach ($results as $result) {
|
foreach ($results as $result) {
|
||||||
// Skip PPT job results (they are handled asynchronously)
|
// Skip PPT job results (they are handled asynchronously)
|
||||||
if (isset($result['job_id'])) {
|
if (isset($result['job_id'])) {
|
||||||
|
|
@ -194,6 +248,7 @@ private function handleZip(
|
||||||
'expire_date' => $expireDate,
|
'expire_date' => $expireDate,
|
||||||
'uploader_name' => $uploaderName,
|
'uploader_name' => $uploaderName,
|
||||||
'uploaded_at' => now(),
|
'uploaded_at' => now(),
|
||||||
|
'sort_order' => $sortOrder++,
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ class Slide extends Model
|
||||||
'expire_date',
|
'expire_date',
|
||||||
'uploader_name',
|
'uploader_name',
|
||||||
'uploaded_at',
|
'uploaded_at',
|
||||||
|
'sort_order',
|
||||||
];
|
];
|
||||||
|
|
||||||
protected function casts(): array
|
protected function casts(): array
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,22 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('slides', function (Blueprint $table) {
|
||||||
|
$table->unsignedInteger('sort_order')->default(0)->after('uploaded_at');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('slides', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('sort_order');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
Loading…
Reference in a new issue