2026-05-08 12:00:02 +02:00
/ * *
* Modal : Embed - URL als exercise _media anlegen und § 11 - Platzhalter einfügen .
* /
import React , { useEffect , useState } from 'react'
import api from '../utils/api'
import {
INLINE _MEDIA _SIZES ,
DEFAULT _INLINE _MEDIA _SIZE ,
sanitizeInlineMediaSize ,
} from '../constants/inlineExerciseMedia'
2026-05-08 12:20:24 +02:00
import { sanitizeInlineMediaCaption } from '../utils/inlineMediaCaption'
2026-05-11 08:44:37 +02:00
const DECL _INIT = {
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
copyright _notice : '' ,
2026-05-11 08:44:37 +02:00
rights _holder _confirmed : false ,
contains _identifiable _persons : null ,
person _consent _confirmed : false ,
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
person _consent _context : '' ,
2026-05-11 08:44:37 +02:00
contains _minors : null ,
parental _consent _confirmed : false ,
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
parental _consent _context : '' ,
2026-05-11 08:44:37 +02:00
contains _music : null ,
music _rights _confirmed : false ,
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
music _rights _context : '' ,
2026-05-11 08:44:37 +02:00
contains _third _party _content : null ,
third _party _rights _confirmed : false ,
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
third _party _rights _context : '' ,
2026-05-11 08:44:37 +02:00
}
function validateDecl ( decl ) {
if ( ! decl . rights _holder _confirmed )
return 'Bitte bestätigen, dass du die erforderlichen Rechte an diesem Medium besitzt.'
if ( decl . contains _identifiable _persons === null )
return 'Bitte angeben, ob erkennbare Personen abgebildet sind.'
if ( decl . contains _identifiable _persons && ! decl . person _consent _confirmed )
return 'Bitte bestätigen, dass die Einwilligungen aller erkennbaren Personen vorliegen.'
if ( decl . contains _minors === null )
return 'Bitte angeben, ob Minderjährige abgebildet sind.'
if ( decl . contains _minors && ! decl . parental _consent _confirmed )
return 'Bitte bestätigen, dass die Einwilligungen der Sorgeberechtigten vorliegen.'
if ( decl . contains _music === null )
return 'Bitte angeben, ob das Medium Musik enthält.'
if ( decl . contains _music && ! decl . music _rights _confirmed )
return 'Bitte bestätigen, dass die erforderlichen Musikrechte vorliegen.'
if ( decl . contains _third _party _content === null )
return 'Bitte angeben, ob fremde geschützte Inhalte enthalten sind.'
if ( decl . contains _third _party _content && ! decl . third _party _rights _confirmed )
return 'Bitte bestätigen, dass die Rechte an allen enthaltenen Fremdmaterialien vorliegen.'
return ''
}
2026-05-08 12:00:02 +02:00
/ * *
* @ param { {
* open : boolean ,
* onClose : ( ) => void ,
* exerciseId : number ,
* onMediaListChanged : ( ) => Promise < void > ,
2026-05-08 12:20:24 +02:00
* onInserted : ( exerciseMediaId : number , displaySize : string , caption ? : string ) => void ,
2026-05-08 12:00:02 +02:00
* } } props
* /
export default function ExerciseInlineEmbedModal ( {
open ,
onClose ,
exerciseId ,
onMediaListChanged ,
onInserted ,
} ) {
const [ url , setUrl ] = useState ( '' )
const [ title , setTitle ] = useState ( '' )
const [ displaySize , setDisplaySize ] = useState ( DEFAULT _INLINE _MEDIA _SIZE )
const [ busy , setBusy ] = useState ( false )
2026-05-11 08:44:37 +02:00
const [ decl , setDecl ] = useState ( { ... DECL _INIT } )
const [ declErr , setDeclErr ] = useState ( '' )
const setDeclField = ( key , val ) => setDecl ( ( d ) => ( { ... d , [ key ] : val } ) )
2026-05-08 12:00:02 +02:00
useEffect ( ( ) => {
if ( ! open ) return
setUrl ( '' )
setTitle ( '' )
setDisplaySize ( DEFAULT _INLINE _MEDIA _SIZE )
2026-05-11 08:44:37 +02:00
setDecl ( { ... DECL _INIT } )
setDeclErr ( '' )
2026-05-08 12:00:02 +02:00
} , [ open ] )
2026-05-11 08:44:37 +02:00
const submit = async ( ) => {
2026-05-08 12:00:02 +02:00
const u = url . trim ( )
if ( ! u ) {
alert ( 'Bitte eine Embed-URL eingeben (https://…).' )
return
}
2026-05-11 08:44:37 +02:00
const validErr = validateDecl ( decl )
if ( validErr ) {
setDeclErr ( validErr )
return
}
setDeclErr ( '' )
2026-05-08 12:00:02 +02:00
const size = sanitizeInlineMediaSize ( displaySize )
const fd = new FormData ( )
fd . append ( 'embed_url' , u )
fd . append ( 'media_type' , 'video' )
fd . append ( 'title' , title . trim ( ) )
fd . append ( 'description' , '' )
fd . append ( 'context' , 'ablauf' )
fd . append ( 'is_primary' , 'false' )
2026-05-11 08:25:00 +02:00
for ( const [ k , v ] of Object . entries ( decl ) ) {
fd . append ( k , String ( v ) )
}
2026-05-08 12:00:02 +02:00
setBusy ( true )
try {
const row = await api . uploadExerciseMedia ( exerciseId , fd )
const mid = row ? . id
if ( mid == null ) {
throw new Error ( 'Antwort ohne exercise_media-ID' )
}
await onMediaListChanged ( )
2026-05-08 12:20:24 +02:00
const cap = sanitizeInlineMediaCaption (
title . trim ( ) || u . replace ( /^https?:\/\//i , '' ) . slice ( 0 , 96 ) ,
)
onInserted ( Number ( mid ) , size , cap )
2026-05-08 12:00:02 +02:00
onClose ( )
} catch ( e ) {
alert ( e . message || String ( e ) )
} finally {
setBusy ( false )
}
}
if ( ! open ) return null
return (
2026-05-11 08:44:37 +02:00
< div className = "admin-modal-backdrop" role = "presentation" onClick = { ( e ) => e . target === e . currentTarget && ! busy && onClose ( ) } >
2026-05-08 12:00:02 +02:00
< div
className = "admin-modal-sheet"
role = "dialog"
aria - modal = "true"
aria - labelledby = "rte-inline-embed-title"
2026-05-11 08:44:37 +02:00
style = { { maxWidth : '480px' , width : '100%' , maxHeight : '90vh' , display : 'flex' , flexDirection : 'column' } }
2026-05-08 12:00:02 +02:00
onClick = { ( e ) => e . stopPropagation ( ) }
>
< div className = "admin-modal-sheet__header" >
< h3 id = "rte-inline-embed-title" className = "admin-modal-sheet__title" >
Embed im Textfeld
< / h3 >
< button type = "button" className = "btn btn-secondary admin-modal-sheet__close" disabled = { busy } onClick = { onClose } >
Schließen
< / button >
< / div >
2026-05-11 08:44:37 +02:00
< div style = { { overflowY : 'auto' , flex : 1 , padding : '14px 16px' } } >
2026-05-08 12:00:02 +02:00
< label className = "form-label" > Embed - URL < / label >
< input
type = "url"
className = "form-input"
placeholder = "https://…"
value = { url }
onChange = { ( e ) => setUrl ( e . target . value ) }
disabled = { busy }
/ >
< label className = "form-label" style = { { marginTop : '12px' } } >
Titel ( optional )
< / label >
< input
type = "text"
className = "form-input"
value = { title }
onChange = { ( e ) => setTitle ( e . target . value ) }
disabled = { busy }
/ >
< label className = "form-label" style = { { marginTop : '12px' } } >
Darstellung im Text
< / label >
< select className = "form-input" value = { displaySize } onChange = { ( e ) => setDisplaySize ( e . target . value ) } disabled = { busy } >
{ INLINE _MEDIA _SIZES . map ( ( o ) => (
< option key = { o . value } value = { o . value } >
{ o . label }
< / option >
) ) }
< / select >
2026-05-11 08:44:37 +02:00
{ /* P-06 Rechte-Erklärung */ }
< div style = { { marginTop : '18px' , paddingTop : '14px' , borderTop : '1px solid var(--border)' } } >
< p style = { { fontSize : '0.82rem' , fontWeight : 600 , marginBottom : '10px' , color : 'var(--text2)' } } >
Rechte - Erklärung < span style = { { fontWeight : 400 , color : 'var(--text3)' } } > ( VORLÄUFIG – p06 - v1 - conservative ) < / span >
< / p >
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
< div style = { { marginBottom : '10px' } } >
< label htmlFor = "emb-cr" style = { { display : 'block' , fontSize : '0.82rem' , fontWeight : 600 , marginBottom : '3px' } } > Copyright - Angabe ( optional ) < / label >
< input id = "emb-cr" type = "text" className = "form-input" placeholder = "z.B. © 2026 Lars Stommer, CC BY-NC"
value = { decl . copyright _notice } onChange = { ( e ) => setDeclField ( 'copyright_notice' , e . target . value ) }
disabled = { busy } style = { { fontSize : '0.85rem' } } / >
< / div >
2026-05-11 08:44:37 +02:00
< div style = { { display : 'flex' , alignItems : 'flex-start' , gap : '8px' , marginBottom : '10px' } } >
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
< input type = "checkbox" id = "emb-rhc" checked = { decl . rights _holder _confirmed }
2026-05-11 08:44:37 +02:00
onChange = { ( e ) => setDeclField ( 'rights_holder_confirmed' , e . target . checked ) }
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
disabled = { busy } style = { { marginTop : '3px' , flexShrink : 0 } } / >
2026-05-11 08:44:37 +02:00
< label htmlFor = "emb-rhc" style = { { fontSize : '0.85rem' } } >
Ich bestätige , dass ich die erforderlichen Rechte an diesem Medium besitze oder zur Veröffentlichung berechtigt bin . *
< / label >
< / div >
< fieldset style = { { border : 'none' , padding : 0 , marginBottom : '10px' } } >
< legend style = { { fontSize : '0.85rem' , fontWeight : 600 , marginBottom : '4px' } } > Erkennbare Personen abgebildet ? * < / legend >
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
< div style = { { display : 'flex' , gap : '14px' , marginBottom : '4px' } } >
< label style = { { fontSize : '0.85rem' } } > < input type = "radio" name = "emb-cip" checked = { decl . contains _identifiable _persons === true } onChange = { ( ) => setDeclField ( 'contains_identifiable_persons' , true ) } disabled = { busy } / > Ja < / label >
< label style = { { fontSize : '0.85rem' } } > < input type = "radio" name = "emb-cip" checked = { decl . contains _identifiable _persons === false } onChange = { ( ) => setDeclField ( 'contains_identifiable_persons' , false ) } disabled = { busy } / > Nein < / label >
2026-05-11 08:44:37 +02:00
< / div >
{ decl . contains _identifiable _persons === true && (
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
< div style = { { paddingLeft : 2 } } >
< div style = { { display : 'flex' , alignItems : 'flex-start' , gap : '8px' , marginBottom : '4px' } } >
< input type = "checkbox" id = "emb-pcc" checked = { decl . person _consent _confirmed } onChange = { ( e ) => setDeclField ( 'person_consent_confirmed' , e . target . checked ) } disabled = { busy } style = { { marginTop : '3px' , flexShrink : 0 } } / >
< label htmlFor = "emb-pcc" style = { { fontSize : '0.85rem' } } > Einwilligungen aller erkennbaren Personen liegen vor . * < / label >
< / div >
< label style = { { display : 'block' , fontSize : '0.8rem' , color : 'var(--text2)' , marginBottom : '2px' } } > Einwilligungskontext ( optional ) < / label >
< textarea className = "form-input" rows = { 2 } placeholder = "z.B. Schriftliche Einwilligung vom 2026-05-01" value = { decl . person _consent _context } onChange = { ( e ) => setDeclField ( 'person_consent_context' , e . target . value ) } disabled = { busy } style = { { fontSize : '0.82rem' , resize : 'vertical' } } / >
2026-05-11 08:44:37 +02:00
< / div >
) }
< / fieldset >
< fieldset style = { { border : 'none' , padding : 0 , marginBottom : '10px' } } >
< legend style = { { fontSize : '0.85rem' , fontWeight : 600 , marginBottom : '4px' } } > Minderjährige abgebildet ? * < / legend >
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
< div style = { { display : 'flex' , gap : '14px' , marginBottom : '4px' } } >
< label style = { { fontSize : '0.85rem' } } > < input type = "radio" name = "emb-cm" checked = { decl . contains _minors === true } onChange = { ( ) => setDeclField ( 'contains_minors' , true ) } disabled = { busy } / > Ja < / label >
< label style = { { fontSize : '0.85rem' } } > < input type = "radio" name = "emb-cm" checked = { decl . contains _minors === false } onChange = { ( ) => setDeclField ( 'contains_minors' , false ) } disabled = { busy } / > Nein < / label >
2026-05-11 08:44:37 +02:00
< / div >
{ decl . contains _minors === true && (
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
< div style = { { paddingLeft : 2 } } >
< div style = { { display : 'flex' , alignItems : 'flex-start' , gap : '8px' , marginBottom : '4px' } } >
< input type = "checkbox" id = "emb-pcc2" checked = { decl . parental _consent _confirmed } onChange = { ( e ) => setDeclField ( 'parental_consent_confirmed' , e . target . checked ) } disabled = { busy } style = { { marginTop : '3px' , flexShrink : 0 } } / >
< label htmlFor = "emb-pcc2" style = { { fontSize : '0.85rem' } } > Einwilligungen der Sorgeberechtigten liegen vor . * < / label >
< / div >
< label style = { { display : 'block' , fontSize : '0.8rem' , color : 'var(--text2)' , marginBottom : '2px' } } > Einwilligungskontext ( optional ) < / label >
< textarea className = "form-input" rows = { 2 } placeholder = "z.B. Elterliche Einwilligung per E-Mail vom 2026-04-15" value = { decl . parental _consent _context } onChange = { ( e ) => setDeclField ( 'parental_consent_context' , e . target . value ) } disabled = { busy } style = { { fontSize : '0.82rem' , resize : 'vertical' } } / >
2026-05-11 08:44:37 +02:00
< / div >
) }
< / fieldset >
< fieldset style = { { border : 'none' , padding : 0 , marginBottom : '10px' } } >
< legend style = { { fontSize : '0.85rem' , fontWeight : 600 , marginBottom : '4px' } } > Musik enthalten ? * < / legend >
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
< div style = { { display : 'flex' , gap : '14px' , marginBottom : '4px' } } >
< label style = { { fontSize : '0.85rem' } } > < input type = "radio" name = "emb-cmu" checked = { decl . contains _music === true } onChange = { ( ) => setDeclField ( 'contains_music' , true ) } disabled = { busy } / > Ja < / label >
< label style = { { fontSize : '0.85rem' } } > < input type = "radio" name = "emb-cmu" checked = { decl . contains _music === false } onChange = { ( ) => setDeclField ( 'contains_music' , false ) } disabled = { busy } / > Nein < / label >
2026-05-11 08:44:37 +02:00
< / div >
{ decl . contains _music === true && (
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
< div style = { { paddingLeft : 2 } } >
< div style = { { display : 'flex' , alignItems : 'flex-start' , gap : '8px' , marginBottom : '4px' } } >
< input type = "checkbox" id = "emb-mrc" checked = { decl . music _rights _confirmed } onChange = { ( e ) => setDeclField ( 'music_rights_confirmed' , e . target . checked ) } disabled = { busy } style = { { marginTop : '3px' , flexShrink : 0 } } / >
< label htmlFor = "emb-mrc" style = { { fontSize : '0.85rem' } } > Musikrechte ( GEMA / Lizenz ) liegen vor . * < / label >
< / div >
< label style = { { display : 'block' , fontSize : '0.8rem' , color : 'var(--text2)' , marginBottom : '2px' } } > Lizenz / GEMA - Kontext ( optional ) < / label >
< textarea className = "form-input" rows = { 2 } placeholder = "z.B. CC BY 4.0 oder GEMA-Freimeldung Nr. …" value = { decl . music _rights _context } onChange = { ( e ) => setDeclField ( 'music_rights_context' , e . target . value ) } disabled = { busy } style = { { fontSize : '0.82rem' , resize : 'vertical' } } / >
2026-05-11 08:44:37 +02:00
< / div >
) }
< / fieldset >
< fieldset style = { { border : 'none' , padding : 0 , marginBottom : '4px' } } >
< legend style = { { fontSize : '0.85rem' , fontWeight : 600 , marginBottom : '4px' } } > Fremde geschützte Inhalte ( Logos , Grafiken , Fotos Dritter ) ? * < / legend >
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
< div style = { { display : 'flex' , gap : '14px' , marginBottom : '4px' } } >
< label style = { { fontSize : '0.85rem' } } > < input type = "radio" name = "emb-ctpc" checked = { decl . contains _third _party _content === true } onChange = { ( ) => setDeclField ( 'contains_third_party_content' , true ) } disabled = { busy } / > Ja < / label >
< label style = { { fontSize : '0.85rem' } } > < input type = "radio" name = "emb-ctpc" checked = { decl . contains _third _party _content === false } onChange = { ( ) => setDeclField ( 'contains_third_party_content' , false ) } disabled = { busy } / > Nein < / label >
2026-05-11 08:44:37 +02:00
< / div >
{ decl . contains _third _party _content === true && (
feat(p06): Copyright-Feld und Einwilligungskontext in Rechte-Erklaerung
Migration 049: 4 optionale TEXT-Spalten in media_asset_rights_declarations
(person_consent_context, parental_consent_context, music_rights_context,
third_party_rights_context) fuer Freitext zum Einwilligungskontext.
Backend:
- media_rights.py: write_rights_declaration speichert 4 Kontextfelder
- media_assets.py: copyright_notice + 4 Kontextfelder in Bulk-Upload,
RightsDeclarationBody, MediaAssetPatch, MediaBulkPatchBody
- exercises.py: copyright_notice + 4 Kontextfelder in upload_exercise_media,
wird in INSERT gespeichert
Frontend (alle 3 Formulare):
- RightsDeclarationDialog: Copyright-Eingabefeld (immer sichtbar) +
Freitext-Textarea bei jeder Ja-Antwort (Personen, Minderjaehrige,
Musik, Fremdinhalte)
- ExerciseInlineFileMediaModal: gleiche Felder inline im Upload-Tab
- ExerciseInlineEmbedModal: gleiche Felder inline
- api.js: copyright_notice + 4 Kontextfelder in bulkUploadMediaAssets
version: 0.8.77
module: media_rights 1.1.0, media_assets 1.14.0, exercises 2.21.0
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-05-11 09:06:47 +02:00
< div style = { { paddingLeft : 2 } } >
< div style = { { display : 'flex' , alignItems : 'flex-start' , gap : '8px' , marginBottom : '4px' } } >
< input type = "checkbox" id = "emb-tprc" checked = { decl . third _party _rights _confirmed } onChange = { ( e ) => setDeclField ( 'third_party_rights_confirmed' , e . target . checked ) } disabled = { busy } style = { { marginTop : '3px' , flexShrink : 0 } } / >
< label htmlFor = "emb-tprc" style = { { fontSize : '0.85rem' } } > Rechte an allen enthaltenen Fremdmaterialien liegen vor . * < / label >
< / div >
< label style = { { display : 'block' , fontSize : '0.8rem' , color : 'var(--text2)' , marginBottom : '2px' } } > Rechtsgrundlage ( optional ) < / label >
< textarea className = "form-input" rows = { 2 } placeholder = "z.B. Verbandslogo mit Genehmigung vom 2026-03-10" value = { decl . third _party _rights _context } onChange = { ( e ) => setDeclField ( 'third_party_rights_context' , e . target . value ) } disabled = { busy } style = { { fontSize : '0.82rem' , resize : 'vertical' } } / >
2026-05-11 08:44:37 +02:00
< / div >
) }
< / fieldset >
{ declErr && (
< p style = { { color : 'var(--danger)' , fontSize : '0.85rem' , marginTop : '8px' } } > { declErr } < / p >
) }
< / div >
< / div >
< div style = { { padding : '12px 16px' , borderTop : '1px solid var(--border)' , flexShrink : 0 } } >
< button type = "button" className = "btn btn-primary btn-full" disabled = { busy } onClick = { submit } >
2026-05-08 12:00:02 +02:00
{ busy ? 'Speichern…' : 'Hinzufügen & in Text einfügen' }
< / button >
< / div >
< / div >
< / div >
)
}