/ src / lib / dmUtils.ts
dmUtils.ts
 1  import type { NostrEvent } from '@nostrify/nostrify';
 2  
 3  /**
 4   * Validate that an event is a proper DM event
 5   */
 6  export function validateDMEvent(event: NostrEvent): boolean {
 7    // Must be kind 4 (NIP-04 DM)
 8    if (event.kind !== 4) return false;
 9  
10    // Must have a 'p' tag
11    const hasRecipient = event.tags?.some(([name]) => name === 'p');
12    if (!hasRecipient) return false;
13  
14    // Must have content (even if encrypted)
15    if (!event.content) return false;
16  
17    return true;
18  }
19  
20  /**
21   * Get the recipient pubkey from a DM event
22   */
23  export function getRecipientPubkey(event: NostrEvent): string | undefined {
24    return event.tags?.find(([name]) => name === 'p')?.[1];
25  }
26  
27  /**
28   * Get the conversation partner pubkey from a DM event
29   * (the other person in the conversation, not the current user)
30   */
31  export function getConversationPartner(event: NostrEvent, userPubkey: string): string | undefined {
32    const isFromUser = event.pubkey === userPubkey;
33    
34    if (isFromUser) {
35      // If we sent it, the partner is the recipient
36      return getRecipientPubkey(event);
37    } else {
38      // If they sent it, the partner is the author
39      return event.pubkey;
40    }
41  }
42  
43  /**
44   * Format timestamp for display (matches Signal/WhatsApp/Telegram pattern)
45   * Today: Show time (e.g., "2:45 PM")
46   * Yesterday: "Yesterday"
47   * This week: Day name (e.g., "Mon")
48   * This year: Month and day (e.g., "Jan 15")
49   * Older: Full date (e.g., "Jan 15, 2024")
50   */
51  export function formatConversationTime(timestamp: number): string {
52    const date = new Date(timestamp * 1000);
53    const now = new Date();
54    
55    // Start of today (midnight)
56    const todayStart = new Date(now.getFullYear(), now.getMonth(), now.getDate());
57    
58    // Start of yesterday
59    const yesterdayStart = new Date(todayStart);
60    yesterdayStart.setDate(yesterdayStart.getDate() - 1);
61    
62    // Start of this week (assuming week starts on Sunday, adjust if needed)
63    const weekStart = new Date(todayStart);
64    weekStart.setDate(weekStart.getDate() - weekStart.getDay());
65    
66    if (date >= todayStart) {
67      // Today: Show time (e.g., "2:45 PM")
68      return date.toLocaleTimeString(undefined, { hour: 'numeric', minute: '2-digit' });
69    } else if (date >= yesterdayStart) {
70      // Yesterday
71      return 'Yesterday';
72    } else if (date >= weekStart) {
73      // This week: Show day name (e.g., "Monday")
74      return date.toLocaleDateString(undefined, { weekday: 'short' });
75    } else if (date.getFullYear() === now.getFullYear()) {
76      // This year: Show month and day (e.g., "Jan 15")
77      return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });
78    } else {
79      // Older: Show full date (e.g., "Jan 15, 2024")
80      return date.toLocaleDateString(undefined, { month: 'short', day: 'numeric', year: 'numeric' });
81    }
82  }
83  
84  /**
85   * Format timestamp as full date and time for tooltips
86   * e.g., "Mon, Jan 15, 2024, 2:45 PM"
87   */
88  export function formatFullDateTime(timestamp: number): string {
89    const date = new Date(timestamp * 1000);
90    return date.toLocaleString(undefined, { 
91      weekday: 'short',
92      year: 'numeric', 
93      month: 'short', 
94      day: 'numeric', 
95      hour: 'numeric', 
96      minute: '2-digit'
97    });
98  }