bug: note reply always

closes #189
This commit is contained in:
Kieran 2023-02-05 12:32:34 +00:00
parent c0cf92ebf3
commit efa765ea84
Signed by: Kieran
GPG Key ID: DE71CEB3925BE941
3 changed files with 101 additions and 102 deletions

View File

@ -1,9 +1,7 @@
import "./NoteCreator.css"; import "./NoteCreator.css";
import { useState } from "react"; import { useState } from "react";
import Attachment from "Icons/Attachment"; import Attachment from "Icons/Attachment";
import Plus from "Icons/Plus";
import useEventPublisher from "Feed/EventPublisher"; import useEventPublisher from "Feed/EventPublisher";
import { openFile } from "Util"; import { openFile } from "Util";
import Textarea from "Element/Textarea"; import Textarea from "Element/Textarea";
@ -29,110 +27,107 @@ function NotePreview({ note }: NotePreviewProps) {
} }
export interface NoteCreatorProps { export interface NoteCreatorProps {
show: boolean show: boolean
setShow: (s: boolean) => void setShow: (s: boolean) => void
replyTo?: NEvent, replyTo?: NEvent,
onSend?: Function, onSend?: Function,
autoFocus: boolean autoFocus: boolean
} }
export function NoteCreator(props: NoteCreatorProps) { export function NoteCreator(props: NoteCreatorProps) {
const { show, setShow, replyTo, onSend, autoFocus } = props const { show, setShow, replyTo, onSend, autoFocus } = props
const publisher = useEventPublisher(); const publisher = useEventPublisher();
const [note, setNote] = useState<string>(); const [note, setNote] = useState<string>();
const [error, setError] = useState<string>(); const [error, setError] = useState<string>();
const [active, setActive] = useState<boolean>(false); const [active, setActive] = useState<boolean>(false);
const uploader = useFileUpload(); const uploader = useFileUpload();
const hasErrors = (error?.length ?? 0) > 0 const hasErrors = (error?.length ?? 0) > 0
async function sendNote() { async function sendNote() {
if (note) { if (note) {
let ev = replyTo ? await publisher.reply(replyTo, note) : await publisher.note(note); let ev = replyTo ? await publisher.reply(replyTo, note) : await publisher.note(note);
console.debug("Sending note: ", ev); console.debug("Sending note: ", ev);
publisher.broadcast(ev); publisher.broadcast(ev);
setNote(""); setNote("");
setShow(false); setShow(false);
if (typeof onSend === "function") { if (typeof onSend === "function") {
onSend(); onSend();
} }
setActive(false); setActive(false);
}
}
async function attachFile() {
try {
let file = await openFile();
if (file) {
let rx = await uploader.upload(file, file.name);
if (rx.url) {
setNote(n => `${n ? `${n}\n` : ""}${rx.url}`);
} else if (rx?.error) {
setError(rx.error);
} }
}
} catch (error: any) {
setError(error?.message)
} }
}
async function attachFile() { function onChange(ev: any) {
try { const { value } = ev.target
let file = await openFile(); setNote(value)
if (file) { if (value) {
let rx = await uploader.upload(file, file.name); setActive(true)
if (rx.url) { } else {
setNote(n => `${n ? `${n}\n` : ""}${rx.url}`); setActive(false)
} else if (rx?.error) {
setError(rx.error);
}
}
} catch (error: any) {
setError(error?.message)
}
} }
}
function onChange(ev: any) { function cancel(ev: any) {
const { value } = ev.target setShow(false)
setNote(value) setNote("")
if (value) { }
setActive(true)
} else {
setActive(false)
}
}
function cancel(ev: any) { function onSubmit(ev: React.MouseEvent<HTMLButtonElement>) {
setShow(false) ev.stopPropagation();
setNote("") sendNote().catch(console.warn);
} }
function onSubmit(ev: React.MouseEvent<HTMLButtonElement>) { return (
ev.stopPropagation(); <>
sendNote().catch(console.warn); {show && (
} <Modal
className="note-creator-modal"
return ( onClose={() => setShow(false)}
<> >
<button className="note-create-button" type="button" onClick={() => setShow(!show)}> {replyTo && (
<Plus /> <NotePreview note={replyTo} />
</button> )}
{show && ( <div className={`flex note-creator ${replyTo ? 'note-reply' : ''}`}>
<Modal <div className="flex f-col mr10 f-grow">
className="note-creator-modal" <Textarea
onClose={() => setShow(false)} autoFocus={autoFocus}
> className={`textarea ${active ? "textarea--focused" : ""}`}
{replyTo && ( onChange={onChange}
<NotePreview note={replyTo} /> value={note}
)} onFocus={() => setActive(true)}
<div className={`flex note-creator ${replyTo ? 'note-reply' : ''}`}> />
<div className="flex f-col mr10 f-grow"> <button type="button" className="attachment" onClick={(e) => attachFile()}>
<Textarea <Attachment />
autoFocus={autoFocus} </button>
className={`textarea ${active ? "textarea--focused" : ""}`}
onChange={onChange}
value={note}
onFocus={() => setActive(true)}
/>
<button type="button" className="attachment" onClick={(e) => attachFile()}>
<Attachment />
</button>
</div>
{hasErrors && <span className="error">{error}</span>}
</div> </div>
<div className="note-creator-actions"> {hasErrors && <span className="error">{error}</span>}
<button className="secondary" type="button" onClick={cancel}> </div>
Cancel <div className="note-creator-actions">
</button> <button className="secondary" type="button" onClick={cancel}>
<button type="button" onClick={onSubmit}> Cancel
{replyTo ? 'Reply' : 'Send'} </button>
</button> <button type="button" onClick={onSubmit}>
</div> {replyTo ? 'Reply' : 'Send'}
</Modal> </button>
)} </div>
</> </Modal>
); )}
</>
);
} }

View File

@ -1,5 +1,5 @@
import "./Layout.css"; import "./Layout.css";
import { useEffect } from "react" import { useEffect, useState } from "react"
import { useDispatch, useSelector } from "react-redux"; import { useDispatch, useSelector } from "react-redux";
import { Outlet, useNavigate } from "react-router-dom"; import { Outlet, useNavigate } from "react-router-dom";
import Envelope from "Icons/Envelope"; import Envelope from "Icons/Envelope";
@ -18,9 +18,12 @@ import useModeration from "Hooks/useModeration";
import { IndexedUDB, useDb } from "State/Users/Db"; import { IndexedUDB, useDb } from "State/Users/Db";
import { db } from "Db"; import { db } from "Db";
import { bech32ToHex } from "Util"; import { bech32ToHex } from "Util";
import { NoteCreator } from "Element/NoteCreator";
import Plus from "Icons/Plus";
export default function Layout() { export default function Layout() {
const [show, setShow] = useState(false)
const dispatch = useDispatch(); const dispatch = useDispatch();
const navigate = useNavigate(); const navigate = useNavigate();
const { loggedOut, publicKey, relays, notifications, readNotifications, dms, preferences, newUserKey } = useSelector((s: RootState) => s.login); const { loggedOut, publicKey, relays, notifications, readNotifications, dms, preferences, newUserKey } = useSelector((s: RootState) => s.login);
@ -174,8 +177,12 @@ export default function Layout() {
} }
</div> </div>
</header> </header>
<Outlet /> <Outlet />
<button className="note-create-button" type="button" onClick={() => setShow(!show)}>
<Plus />
</button>
<NoteCreator replyTo={undefined} autoFocus={true} show={show} setShow={setShow} />
</div> </div>
) )
} }

View File

@ -4,7 +4,6 @@ import { useSelector } from "react-redux";
import { Link } from "react-router-dom"; import { Link } from "react-router-dom";
import { RootState } from "State/Store"; import { RootState } from "State/Store";
import { NoteCreator } from "Element/NoteCreator";
import Timeline from "Element/Timeline"; import Timeline from "Element/Timeline";
import { HexKey } from "Nostr"; import { HexKey } from "Nostr";
import { TimelineSubject } from "Feed/TimelineFeed"; import { TimelineSubject } from "Feed/TimelineFeed";
@ -16,7 +15,6 @@ const RootTab = {
}; };
export default function RootPage() { export default function RootPage() {
const [show, setShow] = useState(false)
const [loggedOut, pubKey, follows] = useSelector<RootState, [boolean | undefined, HexKey | undefined, HexKey[]]>(s => [s.login.loggedOut, s.login.publicKey, s.login.follows]); const [loggedOut, pubKey, follows] = useSelector<RootState, [boolean | undefined, HexKey | undefined, HexKey[]]>(s => [s.login.loggedOut, s.login.publicKey, s.login.follows]);
const [tab, setTab] = useState(RootTab.Posts); const [tab, setTab] = useState(RootTab.Posts);
@ -45,8 +43,7 @@ export default function RootPage() {
</div> </div>
</div></> : null} </div></> : null}
{followHints()} {followHints()}
<Timeline key={tab} subject={timelineSubect} postsOnly={tab === RootTab.Posts} method={"TIME_RANGE"} window={tab === RootTab.Global ? 60 : undefined}/> <Timeline key={tab} subject={timelineSubect} postsOnly={tab === RootTab.Posts} method={"TIME_RANGE"} window={tab === RootTab.Global ? 60 : undefined} />
<NoteCreator replyTo={undefined} autoFocus={true} show={show} setShow={setShow} />
</> </>
); );
} }