import { AttachFileOutlined, FormatAlignLeft } from '@mui/icons-material' import Navigation from '@mui/icons-material/Navigation' import React, { useCallback, useMemo, useState, useRef, memo } from 'react' import { bindActionCreators } from 'redux' import { Button, Fab, Tooltip } from '@mui/material' import { connect } from 'react-redux' import { default as AceEditor } from 'react-ace' import Editor from './Editor' import Message from './Model/Message' import PublishHistory from './PublishHistory' import RetainSwitch from './RetainSwitch' import TopicInput from './TopicInput' import { AppState } from '../../../reducers' import { EditorModeSelect } from './EditorModeSelect' import { globalActions, publishActions } from '../../../actions' import { KeyCodes } from '../../../utils/KeyCodes' interface Props { connectionId?: string topic?: string payload?: string actions: typeof publishActions globalActions: typeof globalActions retain: boolean editorMode: string } function useHistory(): [Array, (topic: string, payload?: string) => void] { const [history, setHistory] = useState>([]) const amendToHistory = useCallback( (topic: string, payload?: string) => { // Remove duplicates let filteredHistory = history.filter(e => e.payload !== payload || e.topic !== topic) filteredHistory = filteredHistory.slice(-7) setHistory([...filteredHistory, { topic, payload, sent: new Date() }]) }, [history] ) return [history, amendToHistory] } function Publish(props: Props) { const editorRef = useRef() const [history, amendToHistory] = useHistory() const focusEditor = useCallback(() => { editorRef.current?.editor.focus() }, [editorRef]) const publish = useCallback(() => { if (!props.connectionId) { return } props.actions.publish(props.connectionId) const topic = props.topic || '' const { payload } = props if (props.connectionId && topic) { amendToHistory(topic, payload) } }, [props, props.connectionId, props.topic, props.payload, amendToHistory]) const handleSubmit = useCallback( (e: React.KeyboardEvent) => { if (e.keyCode === KeyCodes.enter && (e.metaKey || e.ctrlKey)) { e.preventDefault() e.stopPropagation() publish() } }, [publish] ) return useMemo( () => (
), [props.payload, props.editorMode, history, handleSubmit, publish] ) } const EditorMode = memo( (props: { payload?: string editorMode: string focusEditor: () => void actions: typeof publishActions globalActions: typeof globalActions publish: () => void }) => { const updatePayload = props.actions.setPayload const updateMode = useCallback((e: React.ChangeEvent<{}>, value: string) => { props.actions.setEditorMode(value) }, []) const openFile = useCallback(() => { props.actions.openFile() }, []) const formatJson = useCallback(() => { if (props.payload) { try { const str = JSON.stringify(JSON.parse(props.payload), undefined, ' ') updatePayload(str) } catch (error) { props.globalActions.showError(`Format error: ${(error as Error)?.message}`) } } }, [props.payload]) return (
) } ) const FormatJsonButton = React.memo( (props: { editorMode: string; focusEditor: () => void; formatJson: () => void }) => { if (props.editorMode !== 'json') { return null } return ( ) } ) const OpenFileButton = React.memo((props: { editorMode: string; openFile: () => void }) => ( )) const PublishButton = memo((props: { publish: () => void; focusEditor: () => void }) => { const handleClickPublish = useCallback( (e: React.MouseEvent) => { e.stopPropagation() props.publish() }, [props.publish] ) return ( ) }) const mapDispatchToProps = (dispatch: any) => ({ actions: bindActionCreators(publishActions, dispatch), globalActions: bindActionCreators(globalActions, dispatch), }) const mapStateToProps = (state: AppState) => ({ topic: state.publish.manualTopic, payload: state.publish.payload, editorMode: state.publish.editorMode, retain: state.publish.retain, }) export default connect(mapStateToProps, mapDispatchToProps)(Publish)