- {tabs.map(({ key, label }) => (
-
+
+ {/* Tab bar */}
+
+ {tabs.map(({ key, label }) => (
+
+ ))}
+
+
+ {/* Content */}
+ {!user ? (
+
+ Log in to see your notifications.
+
+ ) : isLoading || !hasFetched ? (
+
+ {Array.from({ length: 4 }).map((_, i) => (
+
))}
-
- {/* Content */}
- {!user ? (
-
- Log in to see your notifications.
-
- ) : isLoading || !hasFetched ? (
-
- {Array.from({ length: 4 }).map((_, i) => (
-
- ))}
-
- ) : filteredNotifications.length > 0 ? (
-
- {filteredNotifications.map((event) => (
-
- ))}
-
- ) : (
-
- No notifications yet.
-
- )}
-
+ ) : filteredItems.length > 0 ? (
+
+ {filteredItems.map((item) => (
+
+ ))}
+ {hasNextPage && (
+
+ {isFetchingNextPage && (
+
+
+
+ )}
+
+ )}
+
+ ) : (
+
+ No notifications yet.
+
+ )}
+
);
}
/** Determines the type of notification and renders accordingly. */
-function NotificationItem({ event, isNew }: { event: NostrEvent; isNew: boolean }) {
- switch (event.kind) {
+function NotificationItemView({ item, isNew }: { item: NotificationItem; isNew: boolean }) {
+ switch (item.event.kind) {
case 7:
- return
;
+ return
;
case 6:
- return
;
+ return
;
case 9735:
- return
;
+ return
;
case 1:
- return
;
+ return
;
default:
return null;
}
}
-/** Gets the referenced event ID from an event's tags. */
-function getReferencedEventId(event: NostrEvent): string | undefined {
- const eTag = event.tags.find(([name]) => name === 'e');
- return eTag?.[1];
-}
-
/** Formats a sats amount into a compact human-readable string. */
function formatSats(sats: number): string {
if (sats >= 1_000_000) return `${(sats / 1_000_000).toFixed(1).replace(/\.0$/, '')}M`;
@@ -148,41 +171,53 @@ function formatSats(sats: number): string {
return sats.toString();
}
-/** Wrapper that adds the new-notification indicator and renders the referenced post. */
+/** Wrapper that adds the new-notification indicator. */
function NotificationWrapper({ isNew, children }: { isNew: boolean; children: React.ReactNode }) {
return (
{isNew && (
-
+
)}
{children}
);
}
+/**
+ * Renders the referenced event as a NoteCard.
+ * Uses the pre-fetched event from the notification item, falling back to useEvent.
+ */
+function ReferencedNoteCard({ item }: { item: NotificationItem }) {
+ const referencedEventId = item.event.tags.find(([name]) => name === 'e')?.[1];
+ // Fall back to useEvent if the batch fetch didn't find it
+ const { data: fetchedEvent } = useEvent(
+ item.referencedEvent ? undefined : referencedEventId,
+ );
+ const event = item.referencedEvent ?? fetchedEvent;
+
+ if (!event) return null;
+
+ return
;
+}
+
// ──────────────────────────────────────
// Like Notification
// ──────────────────────────────────────
-function LikeNotification({ event, isNew }: { event: NostrEvent; isNew: boolean }) {
- const referencedEventId = getReferencedEventId(event);
- const { data: referencedEvent } = useEvent(referencedEventId);
-
+function LikeNotification({ item, isNew }: { item: NotificationItem; isNew: boolean }) {
return (
-
+
}
action="reacted to your post"
/>
- {referencedEvent && (
-
- )}
+
);
}
@@ -190,22 +225,17 @@ function LikeNotification({ event, isNew }: { event: NostrEvent; isNew: boolean
// ──────────────────────────────────────
// Repost Notification
// ──────────────────────────────────────
-function RepostNotification({ event, isNew }: { event: NostrEvent; isNew: boolean }) {
- const referencedEventId = getReferencedEventId(event);
- const { data: referencedEvent } = useEvent(referencedEventId);
-
+function RepostNotification({ item, isNew }: { item: NotificationItem; isNew: boolean }) {
return (
}
action="reposted your note"
/>
- {referencedEvent && (
-
- )}
+
);
}
@@ -213,9 +243,8 @@ function RepostNotification({ event, isNew }: { event: NostrEvent; isNew: boolea
// ──────────────────────────────────────
// Zap Notification
// ──────────────────────────────────────
-function ZapNotification({ event, isNew }: { event: NostrEvent; isNew: boolean }) {
- const referencedEventId = getReferencedEventId(event);
- const { data: referencedEvent } = useEvent(referencedEventId);
+function ZapNotification({ item, isNew }: { item: NotificationItem; isNew: boolean }) {
+ const { event } = item;
// Extract zap amount
const zapAmount = useMemo(() => {
@@ -263,9 +292,7 @@ function ZapNotification({ event, isNew }: { event: NostrEvent; isNew: boolean }
action={`zapped you${amountLabel}`}
/>
- {referencedEvent && (
-