/* eslint-disable react/no-children-prop */ import { ChangeEvent, useCallback, useEffect, useMemo, useRef, useState, } from 'react' import { formattedShortTime } from '../../lib/dateFormatting' import { HStack, SpanBox, VStack } from '../elements/LayoutPrimitives' import MarkdownIt from 'markdown-it' import MdEditor from 'react-markdown-editor-lite' import 'react-markdown-editor-lite/lib/index.css' import ReactMarkdown from 'react-markdown' import throttle from 'lodash/throttle' import { updateHighlightMutation } from '../../lib/networking/mutations/updateHighlightMutation' import { Highlight } from '../../lib/networking/fragments/highlightFragment' import { Button } from '../elements/Button' const mdParser = new MarkdownIt() type NoteSectionProps = { placeHolder: string mode: 'edit' | 'preview' sizeMode: 'normal' | 'maximized' setEditMode: (set: 'edit' | 'preview') => void text: string | undefined saveText: (text: string, completed: (success: boolean) => void) => void } export function HighlightNoteBox(props: NoteSectionProps): JSX.Element { const [lastSaved, setLastSaved] = useState(undefined) const saveText = useCallback( (text, updateTime) => { props.saveText(text, (success) => { if (success) { setLastSaved(updateTime) } }) }, [props] ) return ( ) } type HighlightViewNoteProps = { placeHolder: string mode: 'edit' | 'preview' highlight: Highlight sizeMode: 'normal' | 'maximized' setEditMode: (set: 'edit' | 'preview') => void text: string | undefined updateHighlight: (highlight: Highlight) => void } export function HighlightViewNote(props: HighlightViewNoteProps): JSX.Element { const [lastSaved, setLastSaved] = useState(undefined) const saveText = useCallback( (text, updateTime) => { ;(async () => { const success = await updateHighlightMutation({ annotation: text, highlightId: props.highlight?.id, }) if (success) { setLastSaved(updateTime) props.highlight.annotation = text props.updateHighlight(props.highlight) } })() }, [props] ) return ( ) } type MarkdownNote = { placeHolder: string mode: 'edit' | 'preview' sizeMode: 'normal' | 'maximized' setEditMode: (set: 'edit' | 'preview') => void text: string | undefined fillBackground: boolean | undefined lastSaved: Date | undefined saveText: (text: string, updateTime: Date) => void } export function MarkdownNote(props: MarkdownNote): JSX.Element { const editorRef = useRef(null) const [lastChanged, setLastChanged] = useState(undefined) const [errorSaving, setErrorSaving] = useState(undefined) const saveRef = useRef(props.saveText) useEffect(() => { saveRef.current = props.saveText }, [props.lastSaved, lastChanged]) const debouncedSave = useMemo< (text: string, updateTime: Date) => void >(() => { const func = (text: string, updateTime: Date) => { saveRef.current?.(text, updateTime) } return throttle(func, 3000) }, []) const handleEditorChange = useCallback( ( data: { text: string; html: string }, event?: ChangeEvent | undefined ) => { if (event) { event.preventDefault() } const updateTime = new Date() setLastChanged(updateTime) debouncedSave(data.text, updateTime) }, [props.lastSaved, lastChanged] ) return ( <> {props.mode == 'edit' ? ( .section': { borderRight: 'unset', }, '.rc-md-editor .editor-container .sec-md .input': { padding: '10px', borderRadius: '5px', fontSize: '16px', }, }} onKeyDown={(event: React.KeyboardEvent) => { if (event.code.toLowerCase() === 'escape') { props.setEditMode('preview') event.preventDefault() } }} > mdParser.render(text)} onChange={handleEditorChange} /> {errorSaving && ( {errorSaving} )} {props.lastSaved !== undefined ? ( <> {lastChanged === props.lastSaved ? 'Saved' : `Last saved ${formattedShortTime( props.lastSaved.toISOString() )}`} ) : null} {lastChanged !== props.lastSaved && ( )} ) : ( <> *': { m: '0px', }, }} onClick={() => props.setEditMode('edit')} > )} ) }