diff --git a/src/modules/events/components/BookmarkButton.vue b/src/modules/events/components/BookmarkButton.vue
index fc01311..132fb48 100644
--- a/src/modules/events/components/BookmarkButton.vue
+++ b/src/modules/events/components/BookmarkButton.vue
@@ -1,5 +1,5 @@
@@ -43,6 +57,9 @@ function handleToggle() {
:class="bookmarked ? 'text-red-500 hover:text-red-600' : 'text-muted-foreground hover:text-foreground'"
@click.stop="handleToggle"
>
-
+
diff --git a/src/modules/events/composables/useBookmarks.ts b/src/modules/events/composables/useBookmarks.ts
index 8af2f36..57281a9 100644
--- a/src/modules/events/composables/useBookmarks.ts
+++ b/src/modules/events/composables/useBookmarks.ts
@@ -88,9 +88,20 @@ export function useBookmarks() {
/**
* Toggle bookmark for an event. Publishes updated NIP-51 bookmark list.
+ *
+ * Updates local state OPTIMISTICALLY so the UI (heart fill) responds
+ * instantly, then signs + publishes in the background. Signing routes
+ * through the remote LNbits signer and publishing hits relays, so
+ * awaiting both before flipping state made the heart lag ~1s. On
+ * failure the optimistic change is rolled back. Resolves to whether
+ * the change was persisted.
*/
- async function toggleBookmark(eventKind: number, pubkey: string, dTag: string) {
- if (!isAuthenticated.value || !currentUser.value?.pubkey) return
+ async function toggleBookmark(
+ eventKind: number,
+ pubkey: string,
+ dTag: string,
+ ): Promise {
+ if (!isAuthenticated.value || !currentUser.value?.pubkey) return false
const coord = `${eventKind}:${pubkey}:${dTag}`
const newCoords = new Set(state.value.bookmarkedCoords)
@@ -101,6 +112,17 @@ export function useBookmarks() {
newCoords.add(coord)
}
+ // Optimistic flip — preserve the prior state so we can roll back if
+ // signing or publishing fails. Keep lastEventId/lastCreatedAt until
+ // the real event is confirmed.
+ const prevState = state.value
+ state.value = { bookmarkedCoords: newCoords, lastEventId: prevState.lastEventId }
+ ;(state.value as any).lastCreatedAt = (prevState as any).lastCreatedAt
+
+ function rollback() {
+ state.value = prevState
+ }
+
// Build and publish updated bookmark list
const tags: string[][] = Array.from(newCoords).map(c => ['a', c])
@@ -116,19 +138,25 @@ export function useBookmarks() {
signedEvent = await signEventViaLnbits(template)
} catch (err) {
console.error('[useBookmarks] signEventViaLnbits failed:', err)
- return
+ rollback()
+ return false
}
const relayHub = tryInjectService(SERVICE_TOKENS.RELAY_HUB)
- if (!relayHub) return
+ if (!relayHub) {
+ rollback()
+ return false
+ }
const result = await relayHub.publishEvent(signedEvent)
if (result.success > 0) {
- state.value = {
- bookmarkedCoords: newCoords,
- lastEventId: signedEvent.id,
- }
+ state.value = { bookmarkedCoords: newCoords, lastEventId: signedEvent.id }
+ ;(state.value as any).lastCreatedAt = template.created_at
+ return true
}
+
+ rollback()
+ return false
}
onMounted(() => {