fix(p06): RightsDeclarationDialog als echtes Modal (admin-modal-backdrop)
Some checks failed
Deploy Development / deploy (push) Successful in 38s
Test Suite / pytest-backend (push) Successful in 47s
Test Suite / lint-backend (push) Successful in 1s
Test Suite / build-frontend (push) Successful in 10s
Test Suite / playwright-tests (push) Failing after 1m1s

modal-overlay/modal-content existierten nicht im CSS und hatten kein
Styling -- daher kein Backdrop, keine Zentrierung. Umgestellt auf
admin-modal-backdrop + admin-modal-sheet wie alle anderen Modals in der App.

version: 0.8.76

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Lars 2026-05-11 08:51:56 +02:00
parent 9ac8200b41
commit 42aec79ad1

View File

@ -89,149 +89,153 @@ export default function RightsDeclarationDialog({
}
return (
<div className="modal-overlay" role="dialog" aria-modal="true" aria-label="Rechte-Erklärung">
<div className="modal-content" style={{ maxWidth: 560 }}>
<h2 style={{ marginBottom: 4 }}>{titleMap[mode] || titleMap.upload}</h2>
<p style={{ fontSize: '0.85rem', color: 'var(--text2)', marginBottom: 16 }}>
VORLÄUFIG Texte noch nicht juristisch geprüft (p06-v1-conservative).
{isPromotion && (
<> Die bestehende Erklärung gilt nicht für die Sichtbarkeit {visLabel}". Bitte erneut bestätigen.</>
)}
</p>
{/* T1 */}
<div className="form-row" style={{ display: 'flex', alignItems: 'flex-start', gap: 10 }}>
<input
type="checkbox"
id="rhc"
checked={decl.rights_holder_confirmed}
onChange={(e) => setField('rights_holder_confirmed', e.target.checked)}
style={{ marginTop: 3, flexShrink: 0 }}
/>
<label htmlFor="rhc" style={{ fontSize: '0.9rem' }}>
Ich bestätige, dass ich die erforderlichen Urheber- und Nutzungsrechte an diesem Medium besitze
oder rechtmäßig zur Veröffentlichung berechtigt bin. *
</label>
<div className="admin-modal-backdrop" role="presentation" onClick={(e) => e.target === e.currentTarget && handleCancel()}>
<div
className="admin-modal-sheet"
role="dialog"
aria-modal="true"
aria-labelledby="rights-decl-title"
style={{ maxWidth: '520px', width: '100%', maxHeight: '90vh', display: 'flex', flexDirection: 'column' }}
onClick={(e) => e.stopPropagation()}
>
<div className="admin-modal-sheet__header">
<h3 id="rights-decl-title" className="admin-modal-sheet__title">
{titleMap[mode] || titleMap.upload}
</h3>
<button type="button" className="btn btn-secondary admin-modal-sheet__close" onClick={handleCancel}>
Abbrechen
</button>
</div>
{/* T2 / T3 */}
<fieldset style={{ border: 'none', padding: 0, marginTop: 14 }}>
<legend style={{ fontSize: '0.9rem', fontWeight: 600, marginBottom: 6 }}>
Sind erkennbare Personen abgebildet? *
</legend>
<div style={{ display: 'flex', gap: 16 }}>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="cip" checked={decl.contains_identifiable_persons === true}
onChange={() => setField('contains_identifiable_persons', true)} /> Ja
</label>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="cip" checked={decl.contains_identifiable_persons === false}
onChange={() => setField('contains_identifiable_persons', false)} /> Nein
<div style={{ overflowY: 'auto', flex: 1, padding: '14px 16px' }}>
<p style={{ fontSize: '0.82rem', color: 'var(--text3)', marginBottom: 16 }}>
VORLÄUFIG Texte noch nicht juristisch geprüft (p06-v1-conservative).
{isPromotion && (
<> Die bestehende Erklärung gilt nicht für die Sichtbarkeit {visLabel}". Bitte erneut bestätigen.</>
)}
</p>
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, marginBottom: 14 }}>
<input
type="checkbox"
id="rdlg-rhc"
checked={decl.rights_holder_confirmed}
onChange={(e) => setField('rights_holder_confirmed', e.target.checked)}
style={{ marginTop: 3, flexShrink: 0 }}
/>
<label htmlFor="rdlg-rhc" style={{ fontSize: '0.9rem' }}>
Ich bestätige, dass ich die erforderlichen Urheber- und Nutzungsrechte an diesem Medium besitze
oder rechtmäßig zur Veröffentlichung berechtigt bin. *
</label>
</div>
{decl.contains_identifiable_persons === true && (
<div className="form-row" style={{ display: 'flex', alignItems: 'flex-start', gap: 10, marginTop: 8 }}>
<input type="checkbox" id="pcc" checked={decl.person_consent_confirmed}
onChange={(e) => setField('person_consent_confirmed', e.target.checked)}
style={{ marginTop: 3, flexShrink: 0 }} />
<label htmlFor="pcc" style={{ fontSize: '0.9rem' }}>
Ich bestätige, dass die Einwilligungen aller erkennbaren Personen zur Abbildung vorliegen. *
<fieldset style={{ border: 'none', padding: 0, marginBottom: 14 }}>
<legend style={{ fontSize: '0.9rem', fontWeight: 600, marginBottom: 6 }}>Erkennbare Personen abgebildet? *</legend>
<div style={{ display: 'flex', gap: 16 }}>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="rdlg-cip" checked={decl.contains_identifiable_persons === true}
onChange={() => setField('contains_identifiable_persons', true)} /> Ja
</label>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="rdlg-cip" checked={decl.contains_identifiable_persons === false}
onChange={() => setField('contains_identifiable_persons', false)} /> Nein
</label>
</div>
)}
</fieldset>
{decl.contains_identifiable_persons === true && (
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, marginTop: 8 }}>
<input type="checkbox" id="rdlg-pcc" checked={decl.person_consent_confirmed}
onChange={(e) => setField('person_consent_confirmed', e.target.checked)}
style={{ marginTop: 3, flexShrink: 0 }} />
<label htmlFor="rdlg-pcc" style={{ fontSize: '0.9rem' }}>
Einwilligungen aller erkennbaren Personen liegen vor. *
</label>
</div>
)}
</fieldset>
{/* T4 / T5 */}
<fieldset style={{ border: 'none', padding: 0, marginTop: 14 }}>
<legend style={{ fontSize: '0.9rem', fontWeight: 600, marginBottom: 6 }}>
Sind Minderjährige abgebildet? *
</legend>
<div style={{ display: 'flex', gap: 16 }}>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="cm" checked={decl.contains_minors === true}
onChange={() => setField('contains_minors', true)} /> Ja
</label>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="cm" checked={decl.contains_minors === false}
onChange={() => setField('contains_minors', false)} /> Nein
</label>
</div>
{decl.contains_minors === true && (
<div className="form-row" style={{ display: 'flex', alignItems: 'flex-start', gap: 10, marginTop: 8 }}>
<input type="checkbox" id="pcc2" checked={decl.parental_consent_confirmed}
onChange={(e) => setField('parental_consent_confirmed', e.target.checked)}
style={{ marginTop: 3, flexShrink: 0 }} />
<label htmlFor="pcc2" style={{ fontSize: '0.9rem' }}>
Ich bestätige, dass die Einwilligungen der Sorgeberechtigten vorliegen. *
<fieldset style={{ border: 'none', padding: 0, marginBottom: 14 }}>
<legend style={{ fontSize: '0.9rem', fontWeight: 600, marginBottom: 6 }}>Minderjährige abgebildet? *</legend>
<div style={{ display: 'flex', gap: 16 }}>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="rdlg-cm" checked={decl.contains_minors === true}
onChange={() => setField('contains_minors', true)} /> Ja
</label>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="rdlg-cm" checked={decl.contains_minors === false}
onChange={() => setField('contains_minors', false)} /> Nein
</label>
</div>
)}
</fieldset>
{decl.contains_minors === true && (
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, marginTop: 8 }}>
<input type="checkbox" id="rdlg-pcc2" checked={decl.parental_consent_confirmed}
onChange={(e) => setField('parental_consent_confirmed', e.target.checked)}
style={{ marginTop: 3, flexShrink: 0 }} />
<label htmlFor="rdlg-pcc2" style={{ fontSize: '0.9rem' }}>
Einwilligungen der Sorgeberechtigten liegen vor. *
</label>
</div>
)}
</fieldset>
{/* T6 / T7 */}
<fieldset style={{ border: 'none', padding: 0, marginTop: 14 }}>
<legend style={{ fontSize: '0.9rem', fontWeight: 600, marginBottom: 6 }}>
Enthält das Medium Musik? *
</legend>
<div style={{ display: 'flex', gap: 16 }}>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="cmu" checked={decl.contains_music === true}
onChange={() => setField('contains_music', true)} /> Ja
</label>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="cmu" checked={decl.contains_music === false}
onChange={() => setField('contains_music', false)} /> Nein
</label>
</div>
{decl.contains_music === true && (
<div className="form-row" style={{ display: 'flex', alignItems: 'flex-start', gap: 10, marginTop: 8 }}>
<input type="checkbox" id="mrc" checked={decl.music_rights_confirmed}
onChange={(e) => setField('music_rights_confirmed', e.target.checked)}
style={{ marginTop: 3, flexShrink: 0 }} />
<label htmlFor="mrc" style={{ fontSize: '0.9rem' }}>
Ich bestätige, dass die erforderlichen Musikrechte (GEMA / Lizenz) vorliegen. *
<fieldset style={{ border: 'none', padding: 0, marginBottom: 14 }}>
<legend style={{ fontSize: '0.9rem', fontWeight: 600, marginBottom: 6 }}>Musik enthalten? *</legend>
<div style={{ display: 'flex', gap: 16 }}>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="rdlg-cmu" checked={decl.contains_music === true}
onChange={() => setField('contains_music', true)} /> Ja
</label>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="rdlg-cmu" checked={decl.contains_music === false}
onChange={() => setField('contains_music', false)} /> Nein
</label>
</div>
)}
</fieldset>
{decl.contains_music === true && (
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, marginTop: 8 }}>
<input type="checkbox" id="rdlg-mrc" checked={decl.music_rights_confirmed}
onChange={(e) => setField('music_rights_confirmed', e.target.checked)}
style={{ marginTop: 3, flexShrink: 0 }} />
<label htmlFor="rdlg-mrc" style={{ fontSize: '0.9rem' }}>
Musikrechte (GEMA / Lizenz) liegen vor. *
</label>
</div>
)}
</fieldset>
{/* T8 / T9 */}
<fieldset style={{ border: 'none', padding: 0, marginTop: 14 }}>
<legend style={{ fontSize: '0.9rem', fontWeight: 600, marginBottom: 6 }}>
Enthält das Medium fremde geschützte Inhalte (Logos, Grafiken, Fotos Dritter)? *
</legend>
<div style={{ display: 'flex', gap: 16 }}>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="ctpc" checked={decl.contains_third_party_content === true}
onChange={() => setField('contains_third_party_content', true)} /> Ja
</label>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="ctpc" checked={decl.contains_third_party_content === false}
onChange={() => setField('contains_third_party_content', false)} /> Nein
</label>
</div>
{decl.contains_third_party_content === true && (
<div className="form-row" style={{ display: 'flex', alignItems: 'flex-start', gap: 10, marginTop: 8 }}>
<input type="checkbox" id="tprc" checked={decl.third_party_rights_confirmed}
onChange={(e) => setField('third_party_rights_confirmed', e.target.checked)}
style={{ marginTop: 3, flexShrink: 0 }} />
<label htmlFor="tprc" style={{ fontSize: '0.9rem' }}>
Ich bestätige, dass die Rechte an allen enthaltenen Fremdmaterialien vorliegen. *
<fieldset style={{ border: 'none', padding: 0, marginBottom: 4 }}>
<legend style={{ fontSize: '0.9rem', fontWeight: 600, marginBottom: 6 }}>Fremde geschützte Inhalte (Logos, Grafiken, Fotos Dritter)? *</legend>
<div style={{ display: 'flex', gap: 16 }}>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="rdlg-ctpc" checked={decl.contains_third_party_content === true}
onChange={() => setField('contains_third_party_content', true)} /> Ja
</label>
<label style={{ fontSize: '0.9rem' }}>
<input type="radio" name="rdlg-ctpc" checked={decl.contains_third_party_content === false}
onChange={() => setField('contains_third_party_content', false)} /> Nein
</label>
</div>
{decl.contains_third_party_content === true && (
<div style={{ display: 'flex', alignItems: 'flex-start', gap: 10, marginTop: 8 }}>
<input type="checkbox" id="rdlg-tprc" checked={decl.third_party_rights_confirmed}
onChange={(e) => setField('third_party_rights_confirmed', e.target.checked)}
style={{ marginTop: 3, flexShrink: 0 }} />
<label htmlFor="rdlg-tprc" style={{ fontSize: '0.9rem' }}>
Rechte an allen enthaltenen Fremdmaterialien liegen vor. *
</label>
</div>
)}
</fieldset>
{error && (
<p style={{ color: 'var(--danger)', fontSize: '0.85rem', marginTop: 12 }}>{error}</p>
)}
</fieldset>
</div>
{error && (
<p style={{ color: 'var(--danger)', fontSize: '0.85rem', marginTop: 12 }}>{error}</p>
)}
<div style={{ display: 'flex', gap: 10, marginTop: 20, justifyContent: 'flex-end' }}>
<div style={{ padding: '12px 16px', borderTop: '1px solid var(--border)', flexShrink: 0, display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
<button className="btn btn-secondary" type="button" onClick={handleCancel}>
Abbrechen
</button>
<button className="btn btn-primary" type="button" onClick={handleConfirm}>
Bestätigen &amp; fortfahren
Bestätigen &amp; hochladen
</button>
</div>
</div>