Keep a room message in the composer and toast when sending it fails, instead of dropping it silently
This commit is contained in:
parent
790700dd9f
commit
326fb33bca
2 changed files with 69 additions and 58 deletions
|
|
@ -174,65 +174,64 @@
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
const protect = await shouldProtect
|
||||||
const protect = await shouldProtect
|
|
||||||
|
|
||||||
if (eventToEdit) {
|
if (eventToEdit) {
|
||||||
// Don't do anything if message hasn't changed
|
// Don't do anything if message hasn't changed
|
||||||
if (eventToEdit.content === content) {
|
if (eventToEdit.content === content) {
|
||||||
return
|
return clearEventToEdit()
|
||||||
}
|
|
||||||
|
|
||||||
// Delete the previous message, to be republished below with the same timestamp
|
|
||||||
const command = await $deletes.deleteEvent($state.snapshot(eventToEdit), w =>
|
|
||||||
w.setProtected(protect),
|
|
||||||
)
|
|
||||||
|
|
||||||
command.publishToRelays([url])
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// A share is a quote rather than a reply, so setParent prepends the reply's own reference ahead of it.
|
// Delete the previous message, to be republished below with the same timestamp
|
||||||
if (sharedEvent) {
|
const command = await $deletes.deleteEvent($state.snapshot(eventToEdit), w =>
|
||||||
;({content, tags} = await prependParent(sharedEvent, {content, tags}, url))
|
w.setProtected(protect),
|
||||||
}
|
)
|
||||||
|
|
||||||
const eventWriter = writer(Message)
|
command.publishToRelays([url])
|
||||||
.setContent(content)
|
|
||||||
.addTags(...tags)
|
|
||||||
.setProtected(protect)
|
|
||||||
|
|
||||||
if (h) {
|
|
||||||
eventWriter.setRoom(url, h)
|
|
||||||
} else {
|
|
||||||
eventWriter.forceRoutes(relay(url))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (parent) {
|
|
||||||
eventWriter.setParent(parent)
|
|
||||||
}
|
|
||||||
|
|
||||||
const delay = await loadSendDelay()
|
|
||||||
|
|
||||||
const thunk = $thunks.publish({
|
|
||||||
relays: [url],
|
|
||||||
event: stamp(await eventWriter.renderTemplate(), eventToEdit?.created_at),
|
|
||||||
delay,
|
|
||||||
})
|
|
||||||
|
|
||||||
if (delay) {
|
|
||||||
pushToast({
|
|
||||||
timeout: 30_000,
|
|
||||||
children: {
|
|
||||||
component: ThunkToast,
|
|
||||||
props: {thunk},
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
clearParent()
|
|
||||||
clearShare()
|
|
||||||
clearEventToEdit()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// A share is a quote rather than a reply, so setParent prepends the reply's own reference ahead of it.
|
||||||
|
if (sharedEvent) {
|
||||||
|
;({content, tags} = await prependParent(sharedEvent, {content, tags}, url))
|
||||||
|
}
|
||||||
|
|
||||||
|
const eventWriter = writer(Message)
|
||||||
|
.setContent(content)
|
||||||
|
.addTags(...tags)
|
||||||
|
.setProtected(protect)
|
||||||
|
|
||||||
|
if (h) {
|
||||||
|
eventWriter.setRoom(url, h)
|
||||||
|
} else {
|
||||||
|
eventWriter.forceRoutes(relay(url))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parent) {
|
||||||
|
eventWriter.setParent(parent)
|
||||||
|
}
|
||||||
|
|
||||||
|
const delay = await loadSendDelay()
|
||||||
|
|
||||||
|
const thunk = $thunks.publish({
|
||||||
|
relays: [url],
|
||||||
|
event: stamp(await eventWriter.renderTemplate(), eventToEdit?.created_at),
|
||||||
|
delay,
|
||||||
|
})
|
||||||
|
|
||||||
|
if (delay) {
|
||||||
|
pushToast({
|
||||||
|
timeout: 30_000,
|
||||||
|
children: {
|
||||||
|
component: ThunkToast,
|
||||||
|
props: {thunk},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only once it's sent, so a failure leaves the reply or edit in place to try again.
|
||||||
|
clearParent()
|
||||||
|
clearShare()
|
||||||
|
clearEventToEdit()
|
||||||
}
|
}
|
||||||
|
|
||||||
const getElementKey = (element: {id: string}) => element.id
|
const getElementKey = (element: {id: string}) => element.id
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import {writable} from "svelte/store"
|
import {writable} from "svelte/store"
|
||||||
import type {Maybe} from "@welshman/lib"
|
import type {Maybe, MaybeAsync} from "@welshman/lib"
|
||||||
import {MESSAGE} from "@welshman/util"
|
import {MESSAGE} from "@welshman/util"
|
||||||
import type {EventContent} from "@welshman/util"
|
import type {EventContent} from "@welshman/util"
|
||||||
import {escapeHtml, isMobile, preventDefault} from "@lib/html"
|
import {escapeHtml, isMobile, preventDefault} from "@lib/html"
|
||||||
|
|
@ -20,6 +20,7 @@
|
||||||
import {makeEditor} from "@app/editor"
|
import {makeEditor} from "@app/editor"
|
||||||
import {app} from "@app/core"
|
import {app} from "@app/core"
|
||||||
import {getDictation} from "@app/dictation"
|
import {getDictation} from "@app/dictation"
|
||||||
|
import {pushToast} from "@app/toast"
|
||||||
import {DraftKey, type Draft} from "@app/drafts"
|
import {DraftKey, type Draft} from "@app/drafts"
|
||||||
import type {Share} from "@app/share"
|
import type {Share} from "@app/share"
|
||||||
import {onDestroy, onMount} from "svelte"
|
import {onDestroy, onMount} from "svelte"
|
||||||
|
|
@ -29,7 +30,7 @@
|
||||||
h?: string
|
h?: string
|
||||||
onEscape?: () => void
|
onEscape?: () => void
|
||||||
onEditPrevious?: () => void
|
onEditPrevious?: () => void
|
||||||
onSubmit: (event: EventContent) => void
|
onSubmit: (event: EventContent) => MaybeAsync<void>
|
||||||
initialValues?: Share
|
initialValues?: Share
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,7 +101,7 @@
|
||||||
const hidePopover = () => tippy?.hide()
|
const hidePopover = () => tippy?.hide()
|
||||||
|
|
||||||
const submit = async () => {
|
const submit = async () => {
|
||||||
if ($uploading) {
|
if ($uploading || sending) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -108,12 +109,23 @@
|
||||||
const content = ed.getText({blockSeparator: "\n"}).trim()
|
const content = ed.getText({blockSeparator: "\n"}).trim()
|
||||||
const tags = ed.storage.nostr.getEditorTags()
|
const tags = ed.storage.nostr.getEditorTags()
|
||||||
|
|
||||||
onSubmit({content, tags})
|
sending = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
await onSubmit({content, tags})
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Failed to send message", error)
|
||||||
|
|
||||||
|
return pushToast({theme: "error", message: "Failed to send your message."})
|
||||||
|
} finally {
|
||||||
|
sending = false
|
||||||
|
}
|
||||||
|
|
||||||
draftKey?.clear()
|
draftKey?.clear()
|
||||||
ed.chain().clearContent(true).run()
|
ed.chain().clearContent(true).run()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let sending = false
|
||||||
let tippy: Maybe<TippyController> = $state()
|
let tippy: Maybe<TippyController> = $state()
|
||||||
let content = $state(
|
let content = $state(
|
||||||
initialValues?.type === "text" ? initialValues.value : (draftKey?.get()?.content ?? ""),
|
initialValues?.type === "text" ? initialValues.value : (draftKey?.get()?.content ?? ""),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue