/** * @fileoverview Notification List Component for Rantii * @author retoor * @description Displays user notifications and mentions * @keywords notification, list, alerts, mentions, updates */ import { BaseComponent } from './base-component.js'; import { formatRelativeTime } from '../utils/date.js'; class NotificationList extends BaseComponent { init() { this.notifications = []; this.isLoading = false; this.unreadCount = 0; this.render(); this.bindEvents(); } async load() { if (!this.isLoggedIn()) { this.render(); return; } this.isLoading = true; this.render(); try { const result = await this.getApi()?.getNotifications(); if (result?.success) { this.notifications = result.notifications || []; this.unreadCount = result.unread?.total || 0; } } catch (error) { this.notifications = []; } finally { this.isLoading = false; this.render(); } } render() { this.addClass('notification-list'); if (!this.isLoggedIn()) { this.setHtml(`

Sign in to view notifications

`); return; } if (this.isLoading) { this.setHtml(`
`); return; } if (this.notifications.length === 0) { this.setHtml(`

No notifications

`); return; } this.setHtml(`

Notifications

${this.unreadCount > 0 ? ` ` : ''}
${this.notifications.map(notif => ` `).join('')}
`); this.initNotificationItems(); } initNotificationItems() { const items = this.$$('notification-item'); items.forEach(item => { const notifData = item.dataset.notif; if (notifData) { try { const notif = JSON.parse(notifData.replace(/'/g, "'")); item.setNotification(notif); } catch (e) {} } }); } bindEvents() { this.on(this, 'click', this.handleClick); } handleClick(e) { const loginBtn = e.target.closest('.login-btn'); const clearBtn = e.target.closest('.clear-btn'); if (loginBtn) { this.getRouter()?.goToLogin(); return; } if (clearBtn) { this.clearNotifications(); } } async clearNotifications() { try { await this.getApi()?.clearNotifications(); this.unreadCount = 0; this.emit('notifications-cleared'); await this.load(); } catch (error) {} } onConnected() { this.load(); } onDisconnected() { this.isLoading = false; } getUnreadCount() { return this.unreadCount; } refresh() { this.load(); } } customElements.define('notification-list', NotificationList); class NotificationItem extends BaseComponent { init() { this.notifData = null; this.render(); this.bindEvents(); } setNotification(notif) { this.notifData = notif; this.render(); } render() { if (!this.notifData) { this.setHtml(''); return; } const notif = this.notifData; const isUnread = notif.read === 0; const typeLabel = this.getTypeLabel(notif.type); const username = notif.username || notif.user_username || notif.name || 'Someone'; this.addClass('notification-item'); if (isUnread) { this.addClass('unread'); } this.setHtml(`
${this.getTypeIcon(notif.type)}
${username} ${typeLabel}
`); } getTypeLabel(type) { const labels = { 'comment_mention': 'mentioned you', 'comment_content': 'commented on your rant', 'comment_vote': 'upvoted your comment', 'rant_vote': 'upvoted your rant', 'comment_discuss': 'replied to a discussion' }; return labels[type] || 'interacted'; } getTypeIcon(type) { if (type.includes('mention')) { return ``; } if (type.includes('vote')) { return ``; } return ``; } bindEvents() { this.on(this, 'click', this.handleClick); } handleClick() { if (this.notifData?.rant_id) { this.getRouter()?.goToRant( this.notifData.rant_id, this.notifData.comment_id ); } } } customElements.define('notification-item', NotificationItem); export { NotificationList, NotificationItem };