/* eslint-disable react/jsx-props-no-spreading */ import PropTypes from "prop-types" import styled from "styled-components" import React, { useState } from "react" import ReactMde from "react-mde" import * as Showdown from "showdown" import "react-mde/lib/styles/css/react-mde-all.css" import { Link, useHistory } from "react-router-dom" import { useDropzone } from "react-dropzone" import { useWeb3React } from "@web3-react/core" import { Loading } from "./Loading" import { Button } from "./Button" import { useOwnerThread } from "../hooks/useOwnerThread" import { notePath, writePath } from "../utils/paths" import { showdownOptions } from "../utils/showdown" import LockPicker from "./LockPicker" import Checkbox from "./Checkbox" const converter = new Showdown.Converter(showdownOptions()) const Editor = ({ thread: threadId, note: noteId }) => { const { account } = useWeb3React() const { setNoteAttribute, setNoteBody, note, noteThread, loading, save, destroy, uploadFile, } = useOwnerThread(account, threadId, noteId) const onDrop = async (acceptedFiles) => { const { body } = note // keeping track of body, as-is // TODO: support multiple file uploads at once! const file = acceptedFiles[0] const textArea = document.querySelector(".mde-text") const insertAt = textArea.selectionStart const uploadPlaceholder = "\nUploading file..." setNoteBody( body.slice(0, insertAt) + uploadPlaceholder + body.slice(insertAt) ) const url = await uploadFile(file) // We should look at the mimetype for files an respond accordingly // If it is an image, embed as is // if it is an mp3 use an audio player // if it is an mp4, use a video player... let markdown = `\n${url}\n` if (file.type.match("image/*")) { markdown = `![](${url})` } else { // Link to the file markdown = `\n[${file.name}](${url})\n` } setNoteBody(`${body.slice(0, insertAt)}${markdown}${body.slice(insertAt)}`) // WARNING: what happens if the body was changed? // Restore the position textArea.setSelectionRange( insertAt + markdown.length + 1, insertAt + markdown.length + 1 ) } const { getRootProps, getInputProps, isDragActive } = useDropzone({ onDrop, noClick: true, noKeyboard: true, }) const history = useHistory() const [selectedTab, setSelectedTab] = useState("write") const [saving, setSaving] = useState(false) if (loading) { return <Loading /> } const onSave = async (event) => { event.preventDefault() setSaving(true) await save() setSaving(false) return false } const onDestroy = async () => { setSaving(true) await destroy() setSaving(false) history.push(writePath()) return false } const onLockChange = (selected) => { setNoteAttribute( "locks", (selected || []).map((option) => option.value) ) } const draftToggle = () => { setNoteAttribute("draft", !note.attributes.draft) } const isDraft = note.attributes.draft return ( <form className="container" onSubmit={onSave}> <LockPicker identity={account} onLockChange={onLockChange} currentLocks={note.attributes.locks} > <p> Your note will use the{" "} <a target="_blank" rel="noopener noreferrer" href="/#community-lock"> community lock </a> ... but you can also{" "} <a target="_blank" rel="noopener noreferrer" href="https://app.unlock-protocol.com/dashboard" > deploy your own lock </a>{" "} if you want to monetize your own notes. </p> </LockPicker> <div {...getRootProps()}> <input {...getInputProps()} /> {/* Source: https://github.com/andrerpena/react-mde */} <MarkDownEditor isDragActive={isDragActive} value={note.body} onChange={setNoteBody} selectedTab={selectedTab} onTabChange={setSelectedTab} generateMarkdownPreview={(markdown) => Promise.resolve(converter.makeHtml(markdown)) } /> </div> <Checkbox name="draft" checked={isDraft} onChange={draftToggle} label="Draft" /> <Actions> <nav> <Button type="submit" disabled={saving}> Save </Button> </nav> <nav> <Button type="button" disabled={saving} onClick={onDestroy}> Destroy </Button> </nav> {saving && <Loading />} </Actions> <div> {note.attributes.id && note.attributes.id > 0 && ( <> ➡{" "} <Link to={notePath(account, noteThread, note.attributes.id)}> {note.attributes.title} </Link> </> )} </div> </form> ) } Editor.propTypes = { thread: PropTypes.string, note: PropTypes.string, } Editor.defaultProps = { thread: null, note: null, } export default Editor const MarkDownEditor = styled(ReactMde)` border: ${(props) => props.isDragActive ? "1px solid #ff6771" : "1px solid #c8ccd0"}; ` const Actions = styled.div` margin-top: 10px; display: grid; grid-template-columns: repeat(3, 100px); grid-gap: 10px; `