Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 26 additions & 13 deletions src/app/dashboard/media/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { CropIcon, EditIcon, XIcon } from "lucide-react";
import { TrashIcon } from "lucide-react";
import ImageCropEditor from "@/app/_components/posts/image-crop-editor";
import { Button, Input, Label, Select } from "@/app/_components/ui";
import { formatMediaTags, splitMediaTags } from "@/lib/media-tags";
import {
ScrollableModal,
ScrollableModalCard,
Expand Down Expand Up @@ -132,6 +133,10 @@ export default function DashboardMediaPage() {
limit,
mimeType: mimeTypeFilter || undefined,
search: search || undefined,
// Der Statusfilter läuft auf dem Server. Im Browser angewandt betraf er
// nur die geladene Seite: "Ausstehend" blieb leer, obwohl auf Seite 3
// welche lagen, und die Seitenzahl darunter zählte trotzdem alle.
status: statusFilter ? [statusFilter] : undefined,
includeAll: true,
},
{ enabled: !!profile },
Expand Down Expand Up @@ -227,7 +232,7 @@ export default function DashboardMediaPage() {
setEditTitle(media.title ?? "");
setEditCopyright(media.copyright ?? "");
setEditCreator(media.creator ?? "");
setEditTags(typeof media.tags === "string" ? media.tags : "");
setEditTags(formatMediaTags(media.tags));
setEditIsPublic(media.isPublic);
setEditError("");
setShowEditModal(media.id);
Expand All @@ -236,14 +241,24 @@ export default function DashboardMediaPage() {
const handleUpdate = () => {
if (!showEditModal) return;

const name = editName.trim();
if (!name) {
setEditError("Der Name darf nicht leer sein.");
return;
}

updateMutation.mutate({
id: showEditModal,
alt: editAlt || undefined,
caption: editCaption || undefined,
title: editTitle || undefined,
copyright: editCopyright || undefined,
creator: editCreator || undefined,
tags: editTags || undefined,
name,
// `|| null` statt `|| undefined`: ein geleertes Feld soll die Spalte
// leeren. `undefined` heißt für Prisma "nicht anfassen" — der Dialog
// meldete deshalb eine Änderung, die nie stattgefunden hat.
alt: editAlt.trim() || null,
caption: editCaption.trim() || null,
title: editTitle.trim() || null,
copyright: editCopyright.trim() || null,
creator: editCreator.trim() || null,
tags: splitMediaTags(editTags),
isPublic: editIsPublic,
});
};
Expand Down Expand Up @@ -382,9 +397,7 @@ export default function DashboardMediaPage() {
return null;
}

const filteredMedia = statusFilter
? data?.media.filter((m) => m.status === statusFilter)
: data?.media;
const filteredMedia = data?.media;

const isReviewer = hasApprovePermission;
const canDelete = hasDeletePermission;
Expand Down Expand Up @@ -956,16 +969,16 @@ export default function DashboardMediaPage() {
return null;
})()}

{/* Name (read-only) */}
{/* Name */}
<div>
<label className="dark:text-dark-text mb-1 block text-sm font-medium text-gray-700">
Name
</label>
<input
type="text"
value={editName}
disabled
className="dark:bg-dark-background dark:border-dark-border dark:text-dark-muted w-full rounded-lg border border-gray-300 bg-gray-50 px-4 py-2"
onChange={(e) => setEditName(e.target.value)}
className="dark:bg-dark-background dark:border-dark-border dark:text-dark-text focus:border-primary focus:ring-primary w-full rounded-lg border border-gray-300 px-4 py-2 focus:ring-1 focus:outline-none"
/>
</div>

Expand Down
29 changes: 29 additions & 0 deletions src/lib/media-tags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/**
* `Media.tags` ist eine JSON-Spalte, in der historisch zweierlei gelandet ist:
* Arrays aus dem Import und — über ein `z.string()` im Router — einzelne
* Komma-Strings aus dem Dashboard. Beide Formen müssen weiter lesbar bleiben,
* geschrieben wird ab jetzt ausschließlich ein Array.
*/
export function parseMediaTags(value: unknown): string[] {
if (Array.isArray(value)) {
return value
.filter((entry): entry is string => typeof entry === "string")
.map((entry) => entry.trim())
.filter(Boolean);
}
if (typeof value === "string") return splitMediaTags(value);
return [];
}

/** Komma-getrennte Eingabe aus dem Formular in einzelne Tags zerlegen. */
export function splitMediaTags(input: string): string[] {
return input
.split(",")
.map((entry) => entry.trim())
.filter(Boolean);
}

/** Tags für das Formularfeld wieder zu einer Zeile zusammenfassen. */
export function formatMediaTags(value: unknown): string {
return parseMediaTags(value).join(", ");
}
Loading