import "./NoteCreator.css"; import { FormattedMessage, useIntl } from "react-intl"; import { useDispatch, useSelector } from "react-redux"; import { TaggedRawEvent } from "@snort/nostr"; import Icon from "Icons/Icon"; import useEventPublisher from "Feed/EventPublisher"; import { openFile } from "Util"; import Textarea from "Element/Textarea"; import Modal from "Element/Modal"; import ProfileImage from "Element/ProfileImage"; import useFileUpload from "Upload"; import Note from "Element/Note"; import { setShow, setNote, setError, setActive, setPreview, setShowAdvanced, setZapForward, setSensitive, reset, } from "State/NoteCreator"; import type { RootState } from "State/Store"; import { LNURL } from "LNURL"; import messages from "./messages"; interface NotePreviewProps { note: TaggedRawEvent; } function NotePreview({ note }: NotePreviewProps) { return (
{note.content.slice(0, 136)} {note.content.length > 140 && "..."}
); } export function NoteCreator() { const { formatMessage } = useIntl(); const publisher = useEventPublisher(); const uploader = useFileUpload(); const note = useSelector((s: RootState) => s.noteCreator.note); const show = useSelector((s: RootState) => s.noteCreator.show); const error = useSelector((s: RootState) => s.noteCreator.error); const active = useSelector((s: RootState) => s.noteCreator.active); const preview = useSelector((s: RootState) => s.noteCreator.preview); const replyTo = useSelector((s: RootState) => s.noteCreator.replyTo); const showAdvanced = useSelector((s: RootState) => s.noteCreator.showAdvanced); const zapForward = useSelector((s: RootState) => s.noteCreator.zapForward); const sensitive = useSelector((s: RootState) => s.noteCreator.sensitive); const dispatch = useDispatch(); async function sendNote() { if (note) { let extraTags: Array> | undefined; if (zapForward) { try { const svc = new LNURL(zapForward); await svc.load(); extraTags = [svc.getZapTag()]; } catch { dispatch( setError( formatMessage({ defaultMessage: "Invalid LNURL", }) ) ); return; } } if (sensitive) { extraTags ??= []; extraTags.push(["content-warning", sensitive]); } const ev = replyTo ? await publisher.reply(replyTo, note, extraTags) : await publisher.note(note, extraTags); console.debug("Sending note: ", ev); publisher.broadcast(ev); dispatch(reset()); } } async function attachFile() { try { const file = await openFile(); if (file) { const rx = await uploader.upload(file, file.name); if (rx.url) { dispatch(setNote(`${note ? `${note}\n` : ""}${rx.url}`)); } else if (rx?.error) { dispatch(setError(rx.error)); } } } catch (error: unknown) { if (error instanceof Error) { dispatch(setError(error?.message)); } } } function onChange(ev: React.ChangeEvent) { const { value } = ev.target; dispatch(setNote(value)); if (value) { dispatch(setActive(true)); } else { dispatch(setActive(false)); } } function cancel() { dispatch(reset()); } function onSubmit(ev: React.MouseEvent) { ev.stopPropagation(); sendNote().catch(console.warn); } async function loadPreview() { if (preview) { dispatch(setPreview(null)); } else { const tmpNote = await publisher.note(note); if (tmpNote) { dispatch(setPreview(tmpNote)); } } } function getPreviewNote() { if (preview) { return ( ); } } return ( <> {show && ( dispatch(setShow(false))}> {replyTo && } {preview && getPreviewNote()} {!preview && (