Skip to content

Notifications & Messages Improvements โ€‹

Overview โ€‹

Updated the notification system and message handling in Lantern to be more elegant, persistent, and user-friendly.

Changes Implemented โ€‹

1. Notification Persistence โœ… โ€‹

Problem: Notifications disappeared when dismissed or the app reloaded, but would show again on next message.

Solution: Added localStorage-based persistence tracking

  • File: src/screens/dashboard/Dashboard.jsx
  • Implementation:
    • Track dismissed notification IDs in dismissedNotificationIds state (loaded from localStorage on mount)
    • When user dismisses a notification, save the ID to localStorage.lantern_dismissed_notifications
    • Notifications that have been dismissed stay dismissed even after page reload
    • Optional: Add expiration timer to auto-clear old dismissals after 24 hours (see Future Improvements)
javascript
const [dismissedNotificationIds, setDismissedNotificationIds] = useState(() => {
  try {
    const stored = localStorage.getItem('lantern_dismissed_notifications')
    return new Set(stored ? JSON.parse(stored) : [])
  } catch {
    return new Set()
  }
})

const dismissNotification = (id) => {
  setNotifications(prev => prev.filter(n => n.id !== id))
  setDismissedNotificationIds(prev => {
    const updated = new Set(prev)
    updated.add(id)
    try {
      localStorage.setItem('lantern_dismissed_notifications', JSON.stringify(Array.from(updated)))
    } catch (e) {
      console.warn('Failed to persist dismissed notifications:', e)
    }
    return updated
  })
}

2. Redesigned Notification UI โœ… โ€‹

Problem: Notifications were small, indented boxes. They weren't visually prominent or easily scannable.

Solution: Full-width, top-anchored notifications with color coding by type

Changes:

  • Notifications now span the full viewport width with no side padding

  • Stack seamlessly at the top with no gaps between them (border-bottom only)

  • Color coded by type:

    • Blue (bg-blue-600/90) - New Messages
    • Amber (bg-amber-600/90) - Wave Accepted
    • Red (bg-red-600/90) - Errors (future use)
    • Green (bg-green-600/90) - Success (future use)
    • White (bg-white/80) - General messages
  • Each notification includes:

    • Type-specific icon in a colored circle
    • Message text
    • Dismiss button (X) that persists dismissal to localStorage
    • Hover effect with brightness increase for interactivity

File: src/screens/dashboard/Dashboard.jsx

jsx
{/* Full-width Notifications with type-based color coding */}
{notifications.length > 0 && (
  <div className="fixed top-0 left-0 right-0 flex flex-col z-50 w-full">
    {notifications.map(n => {
      // Color scheme per notification type
      const notificationStyles = {
        message: { bg: 'bg-blue-600/90', ... },
        accepted: { bg: 'bg-amber-600/90', ... },
        error: { bg: 'bg-red-600/90', ... },
        success: { bg: 'bg-green-600/90', ... },
        default: { bg: 'bg-white/80', ... }
      }
      // ...render with full-width styling
    })}
  </div>
)}

3. Message Deletion โœ… โ€‹

Problem: Users couldn't delete messages they'd sent in error.

Solution: Added delete button to own messages with hover reveal

Changes:

Chat Component Updates โ€‹

  • File: src/components/Chat.jsx
  • Added Trash2 icon import from lucide-react
  • Added deletingMessageId state to track in-progress deletions
  • Delete button appears on hover (right side of message) for messages you sent ("You")
  • Clicking delete prompts confirmation, then calls deleteMessage()
jsx
{/* Delete button - only for own messages, appears on hover */}
{msg.senderName === 'You' && (
  <button
    onClick={() => handleDeleteMessage(msg.id)}
    disabled={deletingMessageId === msg.id}
    className="absolute -right-10 top-1/2 -translate-y-1/2 opacity-0 group-hover:opacity-100 transition-opacity p-1.5 text-zinc-400 hover:text-red-400 hover:bg-red-500/10 rounded-lg disabled:opacity-50"
    title="Delete message"
  >
    <Trash2 size={16} />
  </button>
)}

Message Service Updates โ€‹

  • File: src/lib/messageService.js
  • Added deleteDoc import from firebase/firestore
  • New deleteMessage() function:
    • Deletes message from connections/{connectionId}/messages/{messageId}
    • Real-time listener automatically updates UI when deletion completes
    • Error handling with user feedback
javascript
export async function deleteMessage(connectionId, messageId) {
  try {
    if (!connectionId || !messageId) {
      throw new Error('Connection ID and Message ID required')
    }
    const messageRef = doc(db, CONNECTIONS_COLLECTION, connectionId, 'messages', messageId)
    await deleteDoc(messageRef)
    console.log(`๐Ÿ—‘๏ธ  Message deleted from connection ${connectionId}`)
  } catch (error) {
    console.error('Error deleting message:', error)
    throw error
  }
}

User Experience Flow โ€‹

Notifications โ€‹

  1. First time seeing notification: Appears at top in full-width color-coded format
  2. User dismisses (via X button):
    • Removed from UI
    • ID saved to localStorage
    • Won't appear again (even if same message type received again)
  3. Page reload: Previously dismissed notifications don't reappear

Messages โ€‹

  1. Hover over own message: Delete button appears on right side
  2. Click delete button: Confirmation dialog
  3. Confirm: Message deleted from Firestore
  4. Real-time sync: Chat updates automatically for both users

Firestore Rules โ€‹

Message deletion respects existing Firestore security rules. Ensure your rules only allow users to delete their own messages:

firestore
allow delete: if request.auth.uid == resource.data.senderId;

See firestore.rules for complete rules.

Files Changed โ€‹

Future Improvements โ€‹

  1. Notification Expiration: Auto-clear dismissed notification IDs after 24 hours to prevent localStorage bloat
  2. Undo Deletion: Add temporary undo button after message deletion (e.g., 5-second window)
  3. Message Edit: Allow editing own messages (timestamp shows "edited")
  4. Notification Sound: Audio cue for message notifications (with mute toggle in settings)
  5. Read Receipts: Show when other user has read your message
  6. Typing Indicator: Show "Them is typing..." while other user composes
  7. Archive Chats: Archive old conversations instead of just closing
  8. Notification Filters: User control over which notification types to show

Testing โ€‹

Notification Persistence โ€‹

  • [ ] Send notification โ†’ dismiss โ†’ reload page โ†’ verify notification doesn't reappear
  • [ ] Clear localStorage โ†’ send same notification again โ†’ should appear
  • [ ] DevTools > Application > LocalStorage > check lantern_dismissed_notifications JSON

Notification UI โ€‹

  • [ ] Verify notifications span full width
  • [ ] Test color coding: Blue (message), Amber (accepted wave), etc.
  • [ ] Verify dismiss button works and persists dismissal
  • [ ] Check responsive behavior on different viewport widths

Message Deletion โ€‹

  • [ ] Send message โ†’ hover โ†’ delete button appears
  • [ ] Click delete โ†’ confirmation dialog โ†’ delete
  • [ ] Verify message disappears for both users (real-time)
  • [ ] Try to delete other user's message (should not show delete button)
  • [ ] Check Firestore rules prevent cross-user deletion

Built with VitePress