diff --git a/packages/app/src/chat/nip4.ts b/packages/app/src/chat/nip4.ts index cc70a44d..958307e3 100644 --- a/packages/app/src/chat/nip4.ts +++ b/packages/app/src/chat/nip4.ts @@ -64,16 +64,15 @@ export class Nip4ChatSystem extends ExternalStore> implements ChatSy {} as Record>, ); - return [...Object.entries(chats)].map(([k, v]) => - Nip4ChatSystem.createChatObj( - encodeTLVEntries("chat4" as NostrPrefix, { - type: TLVEntryType.Author, - value: k, - length: 32, - }), - v, - ), - ); + return [...Object.entries(chats)].map(([k, v]) => Nip4ChatSystem.createChatObj(Nip4ChatSystem.makeChatId(k), v)); + } + + static makeChatId(pubkey: string) { + return encodeTLVEntries("chat4" as NostrPrefix, { + type: TLVEntryType.Author, + value: pubkey, + length: 32, + }); } static createChatObj(id: string, messages: Array) { diff --git a/packages/app/src/service-worker.ts b/packages/app/src/service-worker.ts index 66b2f676..72a0225f 100644 --- a/packages/app/src/service-worker.ts +++ b/packages/app/src/service-worker.ts @@ -6,6 +6,7 @@ declare const self: ServiceWorkerGlobalScope & { import { NostrLink, NostrPrefix, tryParseNostrLink } from "@snort/system"; import { formatShort } from "Number"; import { defaultAvatar, hexToBech32 } from "SnortUtils"; +import { Nip4ChatSystem } from "chat/nip4"; import { clientsClaim } from "workbox-core"; import { PrecacheEntry, precacheAndRoute } from "workbox-precaching"; @@ -56,14 +57,33 @@ interface CompactProfile { self.addEventListener("notificationclick", event => { const id = event.notification.tag as string; + const ev = JSON.parse(event.notification.data) as PushNotification; + event.waitUntil( (async () => { const windows = await self.clients.matchAll({ type: "window" }); - const url = `/${id}`; + const url = () => { + if (ev.type === PushType.Zap || ev.type === PushType.Reaction) { + const mention = ev.data as CompactReaction; + if (mention.event) { + return `/${new NostrLink( + NostrPrefix.Event, + mention.event, + undefined, + mention.author.pubkey, + undefined, + ).encode()}`; + } + } else if (ev.type == PushType.DirectMessage) { + const reaction = ev.data as CompactReaction; + return `/chat/${Nip4ChatSystem.makeChatId(reaction.author.pubkey)}`; + } + return `/${id}`; + }; for (const client of windows) { - if (client.url === url && "focus" in client) return client.focus(); + if (client.url === url() && "focus" in client) return client.focus(); } - if (self.clients.openWindow) return self.clients.openWindow(url); + if (self.clients.openWindow) return self.clients.openWindow(url()); })(), ); }); @@ -76,25 +96,19 @@ self.addEventListener("push", async e => { switch (data.type) { case PushType.Mention: { const evx = data.data as CompactMention; - await self.registration.showNotification( - `${displayNameOrDefault(evx.author)} replied`, - makeNotification(data.type, evx), - ); + await self.registration.showNotification(`${displayNameOrDefault(evx.author)} replied`, makeNotification(data)); break; } case PushType.Reaction: { const evx = data.data as CompactReaction; - await self.registration.showNotification( - `${displayNameOrDefault(evx.author)} reacted`, - makeNotification(data.type, evx), - ); + await self.registration.showNotification(`${displayNameOrDefault(evx.author)} reacted`, makeNotification(data)); break; } case PushType.Zap: { const evx = data.data as CompactReaction; await self.registration.showNotification( `${displayNameOrDefault(evx.author)} zapped${evx.amount ? ` ${formatShort(evx.amount)} sats` : ""}`, - makeNotification(data.type, evx), + makeNotification(data), ); break; } @@ -102,7 +116,7 @@ self.addEventListener("push", async e => { const evx = data.data as CompactReaction; await self.registration.showNotification( `${displayNameOrDefault(evx.author)} reposted`, - makeNotification(data.type, evx), + makeNotification(data), ); break; } @@ -110,7 +124,7 @@ self.addEventListener("push", async e => { const evx = data.data as CompactReaction; await self.registration.showNotification( `${displayNameOrDefault(evx.author)} sent you a DM`, - makeNotification(data.type, evx), + makeNotification(data), ); break; } @@ -143,25 +157,29 @@ function displayNameOrDefault(p: CompactProfile) { return hexToBech32("npub", p.pubkey).slice(0, 12); } -function makeNotification(type: PushType, evx: CompactMention | CompactReaction) { +function makeNotification(n: PushNotification) { + const evx = n.data as CompactMention | CompactReaction; + + const body = () => { + if (n.type === PushType.Mention) { + return ("mentions" in evx ? replaceMentions(evx.content, evx.mentions) : evx.content).substring(0, 250); + } else if (n.type === PushType.Reaction) { + if (evx.content === "+") return "💜"; + if (evx.content === "-") return "👎"; + return evx.content; + } else if (n.type === PushType.DirectMessage) { + return ""; + } else if (n.type === PushType.Repost) { + return ""; + } + return evx.content.substring(0, 250); + }; return { - body: (() => { - if (type === PushType.Mention) { - return ("mentions" in evx ? replaceMentions(evx.content, evx.mentions) : evx.content).substring(0, 250); - } else if (type === PushType.Reaction) { - if (evx.content === "+") return "💜"; - if (evx.content === "-") return "👎"; - return evx.content; - } else if (type === PushType.DirectMessage) { - return ""; - } else if (type === PushType.Repost) { - return ""; - } - return evx.content.substring(0, 250); - })(), + body: body(), icon: evx.author.avatar ?? defaultAvatar(evx.author.pubkey), badge: CONFIG.appleTouchIconUrl, timestamp: evx.created_at * 1000, tag: new NostrLink(NostrPrefix.Event, evx.id, undefined, evx.author.pubkey, undefined).encode(), + data: JSON.stringify(n), }; }