fix: use RichEditor with readOnly prop instead of raw HTML for locked/invalidated offers

RichEditor now supports readOnly prop — hides toolbar and disables
editing via ReactQuill's built-in readOnly. Content renders with
proper Quill CSS (list margins, indentation, fonts) instead of
broken browser defaults from dangerouslySetInnerHTML.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
BOHA
2026-03-24 11:23:34 +01:00
parent b1aaec4fb6
commit 9e6ce4359a
2 changed files with 13 additions and 19 deletions

View File

@@ -64,23 +64,25 @@ interface RichEditorProps {
onChange: (value: string) => void onChange: (value: string) => void
placeholder?: string placeholder?: string
minHeight?: string minHeight?: string
readOnly?: boolean
} }
export default function RichEditor({ export default function RichEditor({
value, value,
onChange, onChange,
placeholder = 'Obsah...', placeholder = 'Obsah...',
minHeight = '120px' minHeight = '120px',
readOnly = false,
}: RichEditorProps) { }: RichEditorProps) {
const quillRef = useRef<ReactQuill>(null) const quillRef = useRef<ReactQuill>(null)
const lastValueRef = useRef(value) const lastValueRef = useRef(value)
const modules = useMemo(() => ({ const modules = useMemo(() => ({
toolbar: TOOLBAR, toolbar: readOnly ? false : TOOLBAR,
clipboard: { clipboard: {
matchVisual: false, matchVisual: false,
}, },
}), []) }), [readOnly])
const handleChange = useCallback((content: string, _delta: any, source: string) => { const handleChange = useCallback((content: string, _delta: any, source: string) => {
if (source !== 'user') return if (source !== 'user') return
@@ -99,6 +101,7 @@ export default function RichEditor({
modules={modules} modules={modules}
formats={FORMATS} formats={FORMATS}
placeholder={placeholder} placeholder={placeholder}
readOnly={readOnly}
/> />
</div> </div>
) )

View File

@@ -1097,22 +1097,13 @@ export default function OfferDetail() {
<div style={{ marginTop: '0.5rem' }}> <div style={{ marginTop: '0.5rem' }}>
<label className="admin-form-label">Obsah</label> <label className="admin-form-label">Obsah</label>
{(isInvalidated || isLockedByOther) ? ( <RichEditor
<div className="rich-editor"> value={section.content}
<div onChange={(val) => setSections(prev => prev.map((s, i) => i === idx ? { ...s, content: val } : s))}
className="ql-editor" placeholder="Obsah sekce..."
style={{ minHeight: '80px', background: 'var(--bg-primary)', border: '1px solid var(--border-color)', borderRadius: 'var(--border-radius-sm)', cursor: 'default', overflowWrap: 'anywhere', wordBreak: 'break-word' }} minHeight="120px"
dangerouslySetInnerHTML={{ __html: section.content || '<em style="color: var(--text-tertiary)">Prázdný obsah</em>' }} readOnly={isInvalidated || isLockedByOther}
/> />
</div>
) : (
<RichEditor
value={section.content}
onChange={(val) => setSections(prev => prev.map((s, i) => i === idx ? { ...s, content: val } : s))}
placeholder="Obsah sekce..."
minHeight="120px"
/>
)}
</div> </div>
</div> </div>
))} ))}