From 000e78e97676d2eb917b0cec9ba75aeb4c4a0805 Mon Sep 17 00:00:00 2001 From: Lars Date: Mon, 11 May 2026 08:25:00 +0200 Subject: [PATCH] fix(p06): RightsDeclarationDialog in Exercise-Upload-Modals integriert ExerciseInlineFileMediaModal (Upload-Tab) und ExerciseInlineEmbedModal zeigen jetzt den vollstaendigen P-06-Einwilligungsdialog bevor der API-Call ausgefuehrt wird. Vorher wurde der Backend-Fehler (400) als nicht benutzbarer browser alert angezeigt. - ExerciseInlineFileMediaModal: handleUploadAndInsert oeffnet Dialog, doUploadWithDecl haengt die 9 P-06-Felder an FormData an - ExerciseInlineEmbedModal: submit oeffnet Dialog, doSubmitWithDecl haengt P-06-Felder an FormData an - Backdrop-Click deaktiviert wenn Dialog offen version: 0.8.76 Co-Authored-By: Claude Sonnet 4.6 --- backend/version.py | 9 ++++++- .../components/ExerciseInlineEmbedModal.jsx | 24 +++++++++++++++++-- .../ExerciseInlineFileMediaModal.jsx | 23 ++++++++++++++++-- frontend/src/version.js | 4 +++- 4 files changed, 54 insertions(+), 6 deletions(-) diff --git a/backend/version.py b/backend/version.py index b19994f..8bdb2a6 100644 --- a/backend/version.py +++ b/backend/version.py @@ -1,6 +1,6 @@ # Shinkan Jinkendo Version Information -APP_VERSION = "0.8.75" +APP_VERSION = "0.8.76" BUILD_DATE = "2026-05-11" DB_SCHEMA_VERSION = "20260511048" @@ -31,6 +31,13 @@ MODULE_VERSIONS = { } CHANGELOG = [ + { + "version": "0.8.76", + "date": "2026-05-11", + "changes": [ + "Fix P-06: RightsDeclarationDialog in ExerciseInlineFileMediaModal (Upload-Tab) und ExerciseInlineEmbedModal integriert; vor jedem Exercise-Media-Upload oeffnet sich der vollstaendige Einwilligungsdialog statt eines nicht-benutzbaren alert()", + ], + }, { "version": "0.8.75", "date": "2026-05-11", diff --git a/frontend/src/components/ExerciseInlineEmbedModal.jsx b/frontend/src/components/ExerciseInlineEmbedModal.jsx index f54e912..6357bdb 100644 --- a/frontend/src/components/ExerciseInlineEmbedModal.jsx +++ b/frontend/src/components/ExerciseInlineEmbedModal.jsx @@ -9,6 +9,7 @@ import { sanitizeInlineMediaSize, } from '../constants/inlineExerciseMedia' import { sanitizeInlineMediaCaption } from '../utils/inlineMediaCaption' +import RightsDeclarationDialog from './RightsDeclarationDialog' /** * @param {{ @@ -30,6 +31,7 @@ export default function ExerciseInlineEmbedModal({ const [title, setTitle] = useState('') const [displaySize, setDisplaySize] = useState(DEFAULT_INLINE_MEDIA_SIZE) const [busy, setBusy] = useState(false) + const [rightsDialogOpen, setRightsDialogOpen] = useState(false) useEffect(() => { if (!open) return @@ -38,12 +40,18 @@ export default function ExerciseInlineEmbedModal({ setDisplaySize(DEFAULT_INLINE_MEDIA_SIZE) }, [open]) - const submit = async () => { + const submit = () => { const u = url.trim() if (!u) { alert('Bitte eine Embed-URL eingeben (https://…).') return } + setRightsDialogOpen(true) + } + + const doSubmitWithDecl = async (decl) => { + setRightsDialogOpen(false) + const u = url.trim() const size = sanitizeInlineMediaSize(displaySize) const fd = new FormData() fd.append('embed_url', u) @@ -52,6 +60,9 @@ export default function ExerciseInlineEmbedModal({ fd.append('description', '') fd.append('context', 'ablauf') fd.append('is_primary', 'false') + for (const [k, v] of Object.entries(decl)) { + fd.append(k, String(v)) + } setBusy(true) try { const row = await api.uploadExerciseMedia(exerciseId, fd) @@ -75,7 +86,15 @@ export default function ExerciseInlineEmbedModal({ if (!open) return null return ( -
e.target === e.currentTarget && !busy && onClose()}> + <> + setRightsDialogOpen(false)} + onConfirm={doSubmitWithDecl} + targetVisibility="private" + mode="upload" + /> +
e.target === e.currentTarget && !busy && !rightsDialogOpen && onClose()}>
+ ) } diff --git a/frontend/src/components/ExerciseInlineFileMediaModal.jsx b/frontend/src/components/ExerciseInlineFileMediaModal.jsx index 8569cd8..8c84633 100644 --- a/frontend/src/components/ExerciseInlineFileMediaModal.jsx +++ b/frontend/src/components/ExerciseInlineFileMediaModal.jsx @@ -10,6 +10,7 @@ import { sanitizeInlineMediaSize, } from '../constants/inlineExerciseMedia' import { sanitizeInlineMediaCaption } from '../utils/inlineMediaCaption' +import RightsDeclarationDialog from './RightsDeclarationDialog' function RtePickerAssetThumb({ asset }) { const id = asset.id @@ -89,6 +90,7 @@ export default function ExerciseInlineFileMediaModal({ const [uploadTitle, setUploadTitle] = useState('') const [displaySize, setDisplaySize] = useState(DEFAULT_INLINE_MEDIA_SIZE) const [uploadInputKey, setUploadInputKey] = useState(0) + const [rightsDialogOpen, setRightsDialogOpen] = useState(false) const assetToExerciseMedia = useMemo(() => { const m = new Map() @@ -182,11 +184,16 @@ export default function ExerciseInlineFileMediaModal({ } } - const handleUploadAndInsert = async () => { + const handleUploadAndInsert = () => { if (!uploadFile) { alert('Bitte eine Datei wählen.') return } + setRightsDialogOpen(true) + } + + const doUploadWithDecl = async (decl) => { + setRightsDialogOpen(false) const size = sanitizeInlineMediaSize(displaySize) const inferred = inferExerciseMediaType(uploadFile) const fd = new FormData() @@ -196,6 +203,9 @@ export default function ExerciseInlineFileMediaModal({ fd.append('description', '') fd.append('context', 'ablauf') fd.append('is_primary', 'false') + for (const [k, v] of Object.entries(decl)) { + fd.append(k, String(v)) + } setBusy(true) setErr(null) try { @@ -232,7 +242,15 @@ export default function ExerciseInlineFileMediaModal({ if (!open) return null return ( -
e.target === e.currentTarget && !busy && onClose()}> + <> + setRightsDialogOpen(false)} + onConfirm={doUploadWithDecl} + targetVisibility="private" + mode="upload" + /> +
e.target === e.currentTarget && !busy && !rightsDialogOpen && onClose()}>
+ ) } diff --git a/frontend/src/version.js b/frontend/src/version.js index 47d4e30..9575302 100644 --- a/frontend/src/version.js +++ b/frontend/src/version.js @@ -1,6 +1,6 @@ // Shinkan Jinkendo Frontend Version -export const APP_VERSION = "0.8.75" +export const APP_VERSION = "0.8.76" export const BUILD_DATE = "2026-05-11" export const PAGE_VERSIONS = { @@ -21,4 +21,6 @@ export const PAGE_VERSIONS = { AdminCatalogsPage: "2.2.0", TrainerContextsPage: "1.0.0", MediaLibraryPage: "1.2.0", // P-06: RightsDeclarationDialog + Altbestand-Indikator + ExerciseInlineFileMediaModal: "1.1.0", // P-06: RightsDeclarationDialog vor Upload + ExerciseInlineEmbedModal: "1.1.0", // P-06: RightsDeclarationDialog vor Embed-Upload }