diff --git a/components/Notification.tsx b/components/Notification.tsx index 3351f41..e3eca58 100644 --- a/components/Notification.tsx +++ b/components/Notification.tsx @@ -1,6 +1,5 @@ import React from 'react'; import { useNostrEvents, useProfile } from "nostr-react"; -import { Card, CardHeader, CardTitle, CardContent, CardFooter, CardDescription } from '@/components/ui/card'; import { NostrEvent, Event, @@ -8,6 +7,7 @@ import { } from "nostr-tools"; import { Avatar, AvatarImage } from './ui/avatar'; import Link from 'next/link'; +import { format } from 'date-fns'; interface NotificationProps { event: NostrEvent; @@ -52,60 +52,69 @@ const Notification: React.FC = ({ event }) => { let name = userData?.name ?? nip19.npubEncode(event.pubkey).slice(0, 8) + ':' + nip19.npubEncode(event.pubkey).slice(-3); let createdAt = new Date(event.created_at * 1000); + + const formatTime = (date: Date) => { + return format(date, 'h:mm a'); + }; - return ( - <> -
- {/* ZAP */} - {event.kind === 9735 && ( -
-

{sats} sats ⚡️

-
- - - + const getNotificationContent = () => { + switch (event.kind) { + case 9735: // ZAP + return ( +
+
+ {sats} ⚡️
-
-

{name} zapped you

-

{createdAt.toLocaleDateString() + ' ' + createdAt.toLocaleTimeString()}

+ + + +
+

{name} zapped you

+

{formatTime(createdAt)}

- )} - {/* FOLLOW */} - {event.kind === 3 && ( -
-

{event.content}

-
- - - + ); + case 3: // FOLLOW + return ( +
+
+ 👋
-
-

{name} started following you

-

{createdAt.toLocaleDateString() + ' ' + createdAt.toLocaleTimeString()}

+ + + +
+

{name} started following you

+

{formatTime(createdAt)}

- )} - {/* REACTION */} - {event.kind === 7 && ( - -
-

{event.content}

-
- - - + ); + case 7: // REACTION + return ( + +
+
+ {event.content}
-
-

{name} reacted to you

-

{createdAt.toLocaleDateString() + ' ' + createdAt.toLocaleTimeString()}

+ + + +
+

{name} reacted to your post

+

{formatTime(createdAt)}

- )} -
-
- + ); + default: + return null; + } + }; + + return ( +
+ {getNotificationContent()} +
); } diff --git a/components/Notifications.tsx b/components/Notifications.tsx index 7bf6201..5194f74 100644 --- a/components/Notifications.tsx +++ b/components/Notifications.tsx @@ -9,6 +9,7 @@ import { nip19, } from "nostr-tools"; import Notification from './Notification'; +import { format, isSameDay, parseISO } from 'date-fns'; interface NotificationsProps { pubkey: string; @@ -52,10 +53,46 @@ const Notifications: React.FC = ({ pubkey }) => { // } // }); - // Create a combined and properly sorted array of all notifications - // const allNotifications = [...(zaps || []), ...(reactions || [])].sort( - // (a, b) => (b.created_at || 0) - (a.created_at || 0) - // ); + // Sort all notifications by date (newest first) + const sortedEvents = [...events].sort( + (a, b) => (b.created_at || 0) - (a.created_at || 0) + ); + + // Group notifications by date + const groupedNotifications = () => { + const groups: { [key: string]: typeof events } = {}; + + sortedEvents.forEach(event => { + const date = new Date(event.created_at * 1000); + const dateKey = format(date, 'yyyy-MM-dd'); + + if (!groups[dateKey]) { + groups[dateKey] = []; + } + + groups[dateKey].push(event); + }); + + return groups; + }; + + // Get formatted date heading based on date + const getDateHeading = (dateStr: string) => { + const date = parseISO(dateStr); + const today = new Date(); + const yesterday = new Date(); + yesterday.setDate(yesterday.getDate() - 1); + + if (isSameDay(date, today)) { + return "Today"; + } else if (isSameDay(date, yesterday)) { + return "Yesterday"; + } else { + return format(date, 'EEEE, MMMM d, yyyy'); + } + }; + + const notificationGroups = groupedNotifications(); return ( <> @@ -67,8 +104,19 @@ const Notifications: React.FC = ({ pubkey }) => { {events.length > 0 ? ( - events.map((notification, index) => ( - + Object.keys(notificationGroups).map(dateKey => ( +
+
+

+ {getDateHeading(dateKey)} +

+
+
+ {notificationGroups[dateKey].map((notification) => ( + + ))} +
+
)) ) : (
No notifications yet
diff --git a/package-lock.json b/package-lock.json index f17d7af..5592599 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "bolt11": "^1.4.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "date-fns": "^4.1.0", "embla-carousel-react": "^8.0.0-rc21", "html5-qrcode": "^2.3.8", "light-bolt11-decoder": "^3.1.1", @@ -6033,6 +6034,16 @@ "dev": true, "license": "BSD-2-Clause" }, + "node_modules/date-fns": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-4.1.0.tgz", + "integrity": "sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, "node_modules/debug": { "version": "4.3.4", "license": "MIT", diff --git a/package.json b/package.json index f1f6e15..aaba63d 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,7 @@ "bolt11": "^1.4.1", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "date-fns": "^4.1.0", "embla-carousel-react": "^8.0.0-rc21", "html5-qrcode": "^2.3.8", "light-bolt11-decoder": "^3.1.1",