diff --git a/app/chat/page.tsx b/app/chat/page.tsx
new file mode 100644
index 0000000..e985983
--- /dev/null
+++ b/app/chat/page.tsx
@@ -0,0 +1,15 @@
+import { Metadata } from 'next';
+import ChatOverview from '@/components/chat/ChatOverview';
+
+export const metadata: Metadata = {
+ title: 'Chats | Lumina',
+ description: 'Your conversations on Nostr',
+};
+
+export default function ChatPage() {
+ return (
+
+
+
+ );
+}
\ No newline at end of file
diff --git a/components/chat/ChatOverview.tsx b/components/chat/ChatOverview.tsx
new file mode 100644
index 0000000..acbe3db
--- /dev/null
+++ b/components/chat/ChatOverview.tsx
@@ -0,0 +1,164 @@
+'use client';
+
+import { useState, useEffect } from 'react';
+import { useNostrEvents, dateToUnix } from 'nostr-react';
+import { useRouter } from 'next/navigation';
+import { Search } from 'lucide-react';
+import { Input } from '@/components/ui/input';
+import { Button } from '@/components/ui/button';
+import { Avatar, AvatarFallback, AvatarImage } from '@/components/ui/avatar';
+import { ScrollArea } from '@/components/ui/scroll-area';
+
+export default function ChatOverview() {
+ const router = useRouter();
+ const [searchQuery, setSearchQuery] = useState('');
+ const [conversations, setConversations] = useState([]);
+ const now = new Date();
+
+ // In a real implementation, this would fetch direct messages (kind 4)
+ // from various relays and process them to show conversations
+ const { events } = useNostrEvents({
+ filter: {
+ kinds: [4], // Kind 4 is direct messages in Nostr
+ since: dateToUnix(new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000)), // Last 30 days
+ },
+ });
+
+ // For demo purposes, let's add some dummy conversations
+ useEffect(() => {
+ // These would be actual pubkeys in a real implementation
+ const dummyConversations = [
+ {
+ id: '1',
+ pubkey: 'npub1abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrst',
+ name: 'Alice',
+ avatar: '',
+ lastMessage: 'Hey, how are you doing?',
+ timestamp: new Date(now.getTime() - 30 * 60 * 1000), // 30 minutes ago
+ unread: 2
+ },
+ {
+ id: '2',
+ pubkey: 'npub2abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrst',
+ name: 'Bob',
+ avatar: '',
+ lastMessage: 'Did you see the new Nostr client everyone is talking about?',
+ timestamp: new Date(now.getTime() - 2 * 60 * 60 * 1000), // 2 hours ago
+ unread: 0
+ },
+ {
+ id: '3',
+ pubkey: 'npub3abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrst',
+ name: 'Charlie',
+ avatar: '',
+ lastMessage: 'Thanks for sharing that article about Bitcoin!',
+ timestamp: new Date(now.getTime() - 1 * 24 * 60 * 60 * 1000), // 1 day ago
+ unread: 0
+ },
+ {
+ id: '4',
+ pubkey: 'npub4abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrst',
+ name: 'Diana',
+ avatar: '',
+ lastMessage: 'Check out this cool zap feature I just discovered!',
+ timestamp: new Date(now.getTime() - 2 * 24 * 60 * 60 * 1000), // 2 days ago
+ unread: 1
+ },
+ {
+ id: '5',
+ pubkey: 'npub5abcdefghijklmnopqrstuvwxyz123456789abcdefghijklmnopqrst',
+ name: 'Evan',
+ avatar: '',
+ lastMessage: 'When are you planning to start your Nostr relay?',
+ timestamp: new Date(now.getTime() - 5 * 24 * 60 * 60 * 1000), // 5 days ago
+ unread: 0
+ },
+ ];
+
+ setConversations(dummyConversations);
+ }, []);
+
+ const filteredConversations = conversations.filter(convo =>
+ convo.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
+ convo.lastMessage.toLowerCase().includes(searchQuery.toLowerCase())
+ );
+
+ const navigateToChat = (pubkey: string) => {
+ // Convert npub to hex format if needed
+ let hexPubkey = pubkey;
+ if (pubkey.startsWith('npub')) {
+ try {
+ // This would actually convert using nostr-tools in real implementation
+ // For demo, we'll just use the pubkey as is
+ hexPubkey = pubkey;
+ } catch (e) {
+ console.error('Failed to convert pubkey', e);
+ }
+ }
+
+ router.push(`/chat/${hexPubkey}`);
+ };
+
+ return (
+
+
+
Messages
+
+
+ setSearchQuery(e.target.value)}
+ />
+
+
+
+
+
+ {filteredConversations.length > 0 ? (
+ filteredConversations.map((convo) => (
+
navigateToChat(convo.pubkey)}
+ >
+
+
+ {convo.name.substring(0, 2).toUpperCase()}
+
+
+
+
+
{convo.name}
+
+ {new Date(convo.timestamp).toLocaleTimeString([], {
+ hour: '2-digit',
+ minute: '2-digit',
+ })}
+
+
+
{convo.lastMessage}
+
+
+ {convo.unread > 0 && (
+
+ {convo.unread}
+
+ )}
+
+ ))
+ ) : (
+
No conversations found
+ )}
+
+
+
+
+
+
+
+ );
+}
\ No newline at end of file