Toast and log unexpected failures in submit handlers that only had try/finally, and move the alerts page's save side effects into saveNotificationSettings

This commit is contained in:
Jon Staab 2026-09-25 23:35:29 -07:00
parent a9ea5e34fe
commit 25e11257aa
50 changed files with 238 additions and 53 deletions

View file

@ -393,7 +393,9 @@ ahead. All ten `*Item` components that appear in a list use it.
## Mutations from a component ## Mutations from a component
flotilla-state covers the writer → command → thunk path. The component around it owns a flotilla-state covers the writer → command → thunk path. The component around it owns a
`loading` flag, awaits the first error, toasts it, and closes: `loading` flag, awaits the first error, toasts it, and closes. Anything thrown on the way (a signer
refusing, a relay unreachable) is logged and toasted in a `catch`, so a bare `try`/`finally` never
lets it escape the handler:
```typescript ```typescript
const submit = async () => { const submit = async () => {
@ -408,6 +410,9 @@ const submit = async () => {
} }
history.back() history.back()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to save your changes."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -139,6 +139,9 @@
draftKey.clear() draftKey.clear()
goto(makeArticlePath(url, getAddress(thunk.options.event))) goto(makeArticlePath(url, getAddress(thunk.options.event)))
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to publish your article."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -115,6 +115,9 @@
draftKey?.clear() draftKey?.clear()
history.back() history.back()
pushToast({message: "Your event has been saved!"}) pushToast({message: "Your event has been saved!"})
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to save your event."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -13,6 +13,7 @@
import {reader, user} from "@app/core" import {reader, user} from "@app/core"
import {getRsvpsByStatus, isAttending, publishRsvp, retractRsvp} from "@app/calendar" import {getRsvpsByStatus, isAttending, publishRsvp, retractRsvp} from "@app/calendar"
import {setEventReminders} from "@app/reminders" import {setEventReminders} from "@app/reminders"
import {pushToast} from "@app/toast"
type Props = { type Props = {
url: string url: string
@ -40,6 +41,9 @@
} }
await setEventReminders(url, event, !retracting && isAttending(status)) await setEventReminders(url, event, !retracting && isAttending(status))
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to update your RSVP."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -53,6 +53,9 @@
} }
await next() await next()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to enable messaging."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -117,6 +117,9 @@
draftKey?.clear() draftKey?.clear()
history.back() history.back()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to publish your listing."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -76,6 +76,9 @@
draftKey.clear() draftKey.clear()
onSubmit() onSubmit()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to send your reply."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -52,14 +52,20 @@
} }
const tags = ed.storage.nostr.getEditorTags() const tags = ed.storage.nostr.getEditorTags()
const thunk = await publishComment({
url,
event,
...(await prependParent(parent, {content, tags}, url)),
})
draftKey.clear() try {
onSubmit(thunk) const thunk = await publishComment({
url,
event,
...(await prependParent(parent, {content, tags}, url)),
})
draftKey.clear()
onSubmit(thunk)
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to send your reply."})
}
} }
let form: HTMLElement let form: HTMLElement

View file

@ -123,6 +123,9 @@
draftKey.clear() draftKey.clear()
history.back() history.back()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to create your funding goal."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -44,12 +44,15 @@
try { try {
await Promise.all(plans.map(save)) await Promise.all(plans.map(save))
clearModals()
next?.()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Your relays couldn't be saved."})
} finally { } finally {
loading = false loading = false
} }
clearModals()
next?.()
} }
</script> </script>

View file

@ -7,6 +7,7 @@
import Icon from "@lib/components/Icon.svelte" import Icon from "@lib/components/Icon.svelte"
import Spinner from "@lib/components/Spinner.svelte" import Spinner from "@lib/components/Spinner.svelte"
import {compressFileForUpload, uploadFileOrFallback} from "@app/uploads" import {compressFileForUpload, uploadFileOrFallback} from "@app/uploads"
import {pushToast} from "@app/toast"
interface Props { interface Props {
file?: File | undefined file?: File | undefined
@ -53,6 +54,9 @@
try { try {
file = await compressFileForUpload(newFile, compressOptions) file = await compressFileForUpload(newFile, compressOptions)
url = (await uploadFileOrFallback(file)).url url = (await uploadFileOrFallback(file)).url
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to process your profile picture."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -66,6 +66,9 @@
roomCode = roomInvite.code roomCode = roomInvite.code
roomInviteError = roomInvite.error roomInviteError = roomInvite.error
} catch (e) {
console.error(e)
claimFailed = true
} finally { } finally {
loading = false loading = false
} }

View file

@ -62,6 +62,9 @@
try { try {
await confirmRecovery() await confirmRecovery()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to recover your key."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -16,6 +16,7 @@
import {session} from "@app/core" import {session} from "@app/core"
import {requirePomadeSession} from "@app/pomade" import {requirePomadeSession} from "@app/pomade"
import KeyRecoveryConfirm from "@app/components/KeyRecoveryConfirm.svelte" import KeyRecoveryConfirm from "@app/components/KeyRecoveryConfirm.svelte"
import {pushToast} from "@app/toast"
const { const {
email, email,
@ -33,6 +34,9 @@
try { try {
await requestRecovery() await requestRecovery()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to request key recovery."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -57,6 +57,9 @@
message: "Something went wrong! Please try again.", message: "Something went wrong! Please try again.",
}) })
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Something went wrong! Please try again."})
} finally { } finally {
loading = undefined loading = undefined
} }
@ -77,6 +80,9 @@
message: "Something went wrong! Please try again.", message: "Something went wrong! Please try again.",
}) })
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Something went wrong! Please try again."})
} finally { } finally {
loading = undefined loading = undefined
} }

View file

@ -68,6 +68,9 @@
try { try {
await confirmRecovery() await confirmRecovery()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to validate email ownership."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -79,6 +79,9 @@
pushToast({message: pin ? "Link updated!" : "Link added!"}) pushToast({message: pin ? "Link updated!" : "Link added!"})
clearModals() clearModals()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to save the link."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -139,6 +139,9 @@
draftKey.clear() draftKey.clear()
history.back() history.back()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to create your poll."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -30,6 +30,9 @@
pushToast({message: "Your profile has been updated!"}) pushToast({message: "Your profile has been updated!"})
clearModals() clearModals()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to update your profile."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -90,7 +90,12 @@
await command.publish().waitForCompletion() await command.publish().waitForCompletion()
pushToast({message: "Banner updated."}) pushToast({message: "Banner updated."})
} else {
pushToast({theme: "error", message: "Failed to upload your banner."})
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to update your banner."})
} finally { } finally {
bannerLoading = false bannerLoading = false
} }

View file

@ -45,6 +45,9 @@
message: `Failed to add relay: ${errorMessage(error)}`, message: `Failed to add relay: ${errorMessage(error)}`,
}) })
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to add relay."})
} finally { } finally {
loading.delete(url) loading.delete(url)
} }

View file

@ -47,6 +47,9 @@
message: `Failed to remove relay: ${errorMessage(error)}`, message: `Failed to remove relay: ${errorMessage(error)}`,
}) })
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to remove relay."})
} finally { } finally {
loading.delete(url) loading.delete(url)
} }

View file

@ -30,24 +30,29 @@
loading = true loading = true
const eventWriter = writer(Report) try {
.setPubkey(event.pubkey) const eventWriter = writer(Report)
.setEventId(event.id) .setPubkey(event.pubkey)
.setReason(reason.toLowerCase()) .setEventId(event.id)
.setContent(content) .setReason(reason.toLowerCase())
.setContent(content)
const reportCommand = await command(eventWriter) const reportCommand = await command(eventWriter)
const error = await reportCommand.publishToRelays([url]).waitForError() const error = await reportCommand.publishToRelays([url]).waitForError()
loading = false if (error) {
return pushToast({theme: "error", message: error})
}
if (error) { history.back()
return pushToast({theme: "error", message: error})
pushToast({message: "Your report has been sent!"})
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to send your report."})
} finally {
loading = false
} }
history.back()
return pushToast({message: "Your report has been sent!"})
} }
let reason = $state("") let reason = $state("")

View file

@ -46,6 +46,9 @@
pushToast({message: "Members assigned!"}) pushToast({message: "Members assigned!"})
back() back()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to assign members."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -34,6 +34,9 @@
pushToast({message: "Role created!"}) pushToast({message: "Role created!"})
back() back()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to create role."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -45,6 +45,9 @@
pushToast({message: "Role updated!"}) pushToast({message: "Role updated!"})
back() back()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to update role."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -37,6 +37,9 @@
const message = await action() const message = await action()
pushToast(message ? {theme: "error", message} : {message: successMessage}) pushToast(message ? {theme: "error", message} : {message: successMessage})
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to update your room membership."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -75,6 +75,9 @@
try { try {
await submit() await submit()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to save the room."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -41,6 +41,9 @@
$app.repository.removeEvent(event.id) $app.repository.removeEvent(event.id)
onResolved?.() onResolved?.()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to dismiss join request."})
} finally { } finally {
loading = false loading = false
} }
@ -58,6 +61,9 @@
pushToast({message: "Member has been added to the room!"}) pushToast({message: "Member has been added to the room!"})
onResolved?.() onResolved?.()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to add member to the room."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -47,6 +47,9 @@
pushToast({message: "Members have successfully been added!"}) pushToast({message: "Members have successfully been added!"})
back() back()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to add members."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -33,6 +33,9 @@
} else { } else {
onJoin() onJoin()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to join the room."})
} finally { } finally {
joining = false joining = false
} }
@ -49,6 +52,9 @@
} else { } else {
pushToast({message: "You have left the room."}) pushToast({message: "You have left the room."})
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to leave the room."})
} finally { } finally {
leaving = false leaving = false
} }

View file

@ -11,6 +11,7 @@
import ModalTitle from "@lib/components/ModalTitle.svelte" import ModalTitle from "@lib/components/ModalTitle.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte"
import ProgressBar from "@app/components/ProgressBar.svelte" import ProgressBar from "@app/components/ProgressBar.svelte"
import {pushToast} from "@app/toast"
type Props = { type Props = {
next: () => void next: () => void
@ -27,6 +28,9 @@
try { try {
await next() await next()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to complete sign up."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -38,6 +38,9 @@
} }
callback() callback()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to request access."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -16,6 +16,7 @@
import SpaceAccessRequest from "@app/components/SpaceAccessRequest.svelte" import SpaceAccessRequest from "@app/components/SpaceAccessRequest.svelte"
import {leaveSpace} from "@app/access" import {leaveSpace} from "@app/access"
import {clearModals, navigate, pushModal} from "@app/modal" import {clearModals, navigate, pushModal} from "@app/modal"
import {pushToast} from "@app/toast"
type Props = { type Props = {
url: string url: string
@ -34,6 +35,9 @@
try { try {
await leaveSpace(url) await leaveSpace(url)
await navigate("/home") await navigate("/home")
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to leave the space."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -73,6 +73,9 @@
try { try {
await submit() await submit()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to save your changes."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -12,6 +12,7 @@
import ModalTitle from "@lib/components/ModalTitle.svelte" import ModalTitle from "@lib/components/ModalTitle.svelte"
import ModalFooter from "@lib/components/ModalFooter.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte"
import {leaveSpace} from "@app/access" import {leaveSpace} from "@app/access"
import {pushToast} from "@app/toast"
const {url} = $props() const {url} = $props()
@ -23,6 +24,9 @@
try { try {
await leaveSpace(url) await leaveSpace(url)
await navigate("/home") await navigate("/home")
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to leave the space."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -69,6 +69,9 @@
try { try {
await joinRelay() await joinRelay()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to accept the invite."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -68,6 +68,9 @@
pushToast({message: "Permissions updated!"}) pushToast({message: "Permissions updated!"})
back() back()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to update permissions."})
} finally { } finally {
saving = false saving = false
} }

View file

@ -58,6 +58,9 @@
pushToast({message: "Roles updated!"}) pushToast({message: "Roles updated!"})
back() back()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to update roles."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -35,6 +35,9 @@
pushToast({message: "Members have successfully been added!"}) pushToast({message: "Members have successfully been added!"})
back() back()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to add members."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -14,6 +14,7 @@
import ModalFooter from "@lib/components/ModalFooter.svelte" import ModalFooter from "@lib/components/ModalFooter.svelte"
import {roomLists} from "@app/core" import {roomLists} from "@app/core"
import {goToMovedSpace} from "@app/routes" import {goToMovedSpace} from "@app/routes"
import {pushToast} from "@app/toast"
type Props = { type Props = {
url: string url: string
@ -30,6 +31,9 @@
try { try {
await $roomLists.migrateRelay(url, newUrl).then(command => command?.publish()) await $roomLists.migrateRelay(url, newUrl).then(command => command?.publish())
await goToMovedSpace(url, newUrl) await goToMovedSpace(url, newUrl)
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to move to the new space."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -19,6 +19,7 @@
import {addTrustedRelay, removeTrustedRelay} from "@app/settings" import {addTrustedRelay, removeTrustedRelay} from "@app/settings"
import {navigate, popModal, pushModal} from "@app/modal" import {navigate, popModal, pushModal} from "@app/modal"
import {roomLists} from "@app/core" import {roomLists} from "@app/core"
import {pushToast} from "@app/toast"
type Props = { type Props = {
url: string url: string
@ -35,6 +36,9 @@
await $roomLists.removeRelay(url).then(publish) await $roomLists.removeRelay(url).then(publish)
await removeTrustedRelay(url) await removeTrustedRelay(url)
navigate("/home") navigate("/home")
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to leave the space."})
} finally { } finally {
loading = false loading = false
} }
@ -48,6 +52,9 @@
relaysPendingTrust.update($r => remove(url, $r)) relaysPendingTrust.update($r => remove(url, $r))
popModal() popModal()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to trust this space."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -83,6 +83,9 @@
draftKey.clear() draftKey.clear()
history.back() history.back()
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to create your thread."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -30,6 +30,9 @@
} else { } else {
clearModals() clearModals()
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to update profile."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -8,6 +8,7 @@
import InfoZapperError from "@app/components/InfoZapperError.svelte" import InfoZapperError from "@app/components/InfoZapperError.svelte"
import {pushModal} from "@app/modal" import {pushModal} from "@app/modal"
import {app} from "@app/core" import {app} from "@app/core"
import {pushToast} from "@app/toast"
type Props = { type Props = {
url?: string url?: string
@ -34,6 +35,9 @@
} else { } else {
pushModal(InfoZapperError, {url, pubkey: event.pubkey}, {replaceState}) pushModal(InfoZapperError, {url, pubkey: event.pubkey}, {replaceState})
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to load zap details."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -1,5 +1,7 @@
import {Capacitor} from "@capacitor/core" import {Capacitor} from "@capacitor/core"
import {notificationSettings, setSpaceNotifications} from "@app/settings" import {notificationSettings, setSpaceNotifications} from "@app/settings"
import {clearBadges} from "@app/notifications"
import {syncEventReminders} from "@app/reminders"
import {pushState} from "@app/push/adapters/common" import {pushState} from "@app/push/adapters/common"
import {ElectronNotifications} from "@app/push/adapters/electron" import {ElectronNotifications} from "@app/push/adapters/electron"
import {WebNotifications} from "@app/push/adapters/web" import {WebNotifications} from "@app/push/adapters/web"
@ -76,3 +78,20 @@ export const optInSpaceNotifications = async (url: string, notify: boolean) => {
await setSpaceNotifications(url, notify) await setSpaceNotifications(url, notify)
} }
} }
export const saveNotificationSettings = async (
values: ReturnType<typeof notificationSettings.get>,
) => {
if (!values.badge) {
clearBadges()
}
const permission = values.push ? await Push.request() : "granted"
if (permission.startsWith("granted")) {
notificationSettings.set(values)
syncEventReminders()
}
return permission
}

View file

@ -14,9 +14,7 @@
import Button from "@lib/components/Button.svelte" import Button from "@lib/components/Button.svelte"
import PageContent from "@lib/components/PageContent.svelte" import PageContent from "@lib/components/PageContent.svelte"
import {pushToast} from "@app/toast" import {pushToast} from "@app/toast"
import {clearBadges} from "@app/notifications" import {saveNotificationSettings} from "@app/push"
import {Push} from "@app/push"
import {syncEventReminders} from "@app/reminders"
import {notificationSettings} from "@app/settings" import {notificationSettings} from "@app/settings"
const reset = () => { const reset = () => {
@ -49,32 +47,23 @@
}) })
} }
if (!settings.badge) { const permission = await saveNotificationSettings($state.snapshot(settings))
clearBadges()
if (permission.startsWith("granted")) {
pushToast({message: "Your settings have been saved!"})
} else {
await sleep(300)
settings.push = false
pushToast({
theme: "error",
message: `Failed to request notification permissions (${permission}).`,
})
} }
} catch (e) {
let permission = "granted" console.error(e)
pushToast({theme: "error", message: "Failed to save your alert settings."})
if (settings.push) {
permission = await Push.request()
if (!permission.startsWith("granted")) {
await sleep(300)
settings.push = false
return pushToast({
theme: "error",
message: `Failed to request notification permissions (${permission}).`,
})
}
}
notificationSettings.set(settings)
syncEventReminders()
pushToast({message: "Your settings have been saved!"})
} finally { } finally {
loading = false loading = false
} }

View file

@ -64,6 +64,9 @@
await $blossomServerLists.setUrls($state.snapshot(blossomServers)).then(publish) await $blossomServerLists.setUrls($state.snapshot(blossomServers)).then(publish)
pushToast({message: "Your settings have been saved!"}) pushToast({message: "Your settings have been saved!"})
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to save your settings."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -42,6 +42,9 @@
} else { } else {
pushToast({message: "Your logs have been sent. Thank you!"}) pushToast({message: "Your logs have been sent. Thank you!"})
} }
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to send your logs."})
} finally { } finally {
sendingLogs = false sendingLogs = false
} }
@ -67,6 +70,9 @@
await publishSettings($settings) await publishSettings($settings)
pushToast({message: "Your settings have been saved!"}) pushToast({message: "Your settings have been saved!"})
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to save your settings."})
} finally { } finally {
loading = false loading = false
} }

View file

@ -128,6 +128,9 @@
await publishSettings({zap_amounts: $settings.zap_amounts}) await publishSettings({zap_amounts: $settings.zap_amounts})
pushToast({message: "Your zap amounts have been saved!"}) pushToast({message: "Your zap amounts have been saved!"})
} catch (e) {
console.error(e)
pushToast({theme: "error", message: "Failed to save your zap amounts."})
} finally { } finally {
zapAmountsLoading = false zapAmountsLoading = false
} }