import { t, i18n } from '../../i18n.js' import { auth } from '../../services/auth.js' import { notificationsService } from '../../services/notifications.js' import { router } from '../../router.js' class PageNotifications extends HTMLElement { constructor() { super() this.loading = true } connectedCallback() { this._unsubs = [] this.render() this.loadNotifications() this._unsubs.push(i18n.subscribe(() => this.render())) this._unsubs.push(notificationsService.subscribe(() => { this.loading = false this.updateContent() })) } disconnectedCallback() { this._unsubs.forEach(fn => fn()) this._unsubs = [] } async loadNotifications() { if (!auth.isLoggedIn()) { this.loading = false this.updateContent() return } await notificationsService.refresh() } render() { this.innerHTML = /* html */`
${this.renderContent()}
` this.setupEventListeners() } updateContent() { const container = this.querySelector('#notifications-content') if (container) { container.innerHTML = this.renderContent() this.setupEventListeners() } } renderContent() { if (!auth.isLoggedIn()) { return /* html */`
🔔

${t('auth.loginRequired')}

` } if (this.loading) { return /* html */`
${Array(3).fill(0).map(() => `
`).join('')}
` } const notifications = notificationsService.notifications if (notifications.length === 0) { return /* html */`
🔔

${t('notifications.empty')}

` } return /* html */`
${notifications.map(n => this.renderNotification(n)).join('')}
` } renderNotification(n) { const typeText = t(`notifications.${n.type}`) const date = new Date(n.date_created) const timeAgo = this.formatTimeAgo(date) return /* html */`
${this.getIcon(n.type)}

${typeText}

${timeAgo}
` } getIcon(type) { const icons = { listing_created: '📝', listing_published: '✅', listing_expired: '⏰', new_message: '💬', favorite_added: '❤️' } return icons[type] || '🔔' } formatTimeAgo(date) { const now = new Date() const diffMs = now - date const diffMin = Math.floor(diffMs / 60000) const diffHours = Math.floor(diffMs / 3600000) const diffDays = Math.floor(diffMs / 86400000) if (diffMin < 1) return t('messages.today') if (diffMin < 60) return `${diffMin} min` if (diffHours < 24) return `${diffHours}h` if (diffDays === 1) return t('messages.yesterday') return t('messages.daysAgo', { days: diffDays }) } setupEventListeners() { this.querySelector('#mark-all-read')?.addEventListener('click', async () => { await notificationsService.markAllRead() this.render() }) this.querySelector('#login-btn')?.addEventListener('click', () => { document.querySelector('auth-modal')?.show('login') }) this.querySelectorAll('.notification-item').forEach(item => { item.addEventListener('click', async (e) => { if (e.target.closest('.notification-delete')) return const id = item.dataset.id const type = item.dataset.type const ref = item.dataset.ref await notificationsService.markRead(id) if (ref) { if (type === 'new_message') { router.navigate(`/messages`) } else { router.navigate(`/listing/${ref}`) } } }) }) this.querySelectorAll('.notification-delete').forEach(btn => { btn.addEventListener('click', async (e) => { e.stopPropagation() await notificationsService.remove(btn.dataset.delete) }) }) } } customElements.define('page-notifications', PageNotifications) const style = document.createElement('style') style.textContent = /* css */` page-notifications .notifications-page { padding: var(--space-lg) 0; } page-notifications .page-header { margin-bottom: var(--space-xl); } page-notifications .page-header-row { display: flex; justify-content: space-between; align-items: center; } page-notifications .page-header h1 { margin: 0; } page-notifications .notifications-list { display: flex; flex-direction: column; gap: 1px; background-color: var(--color-border); border: 1px solid var(--color-border); border-radius: var(--radius-lg); overflow: hidden; } page-notifications .notification-item { display: flex; align-items: center; gap: var(--space-md); padding: var(--space-md) var(--space-lg); background-color: var(--color-bg); cursor: pointer; transition: background-color var(--transition-fast); } page-notifications .notification-item:hover { background-color: var(--color-bg-secondary); } page-notifications .notification-item.unread { background-color: var(--color-bg-secondary); } page-notifications .notification-item.unread .notification-text { font-weight: var(--font-weight-semibold); } page-notifications .notification-icon { font-size: 1.5rem; flex-shrink: 0; filter: grayscale(1); } page-notifications .notification-body { flex: 1; min-width: 0; } page-notifications .notification-text { margin: 0 0 var(--space-xs); font-size: var(--font-size-sm); } page-notifications .notification-time { font-size: var(--font-size-xs); color: var(--color-text-muted); } page-notifications .notification-delete { flex-shrink: 0; opacity: 0; transition: opacity var(--transition-fast); } page-notifications .notification-item:hover .notification-delete { opacity: 1; } page-notifications .empty-state { text-align: center; padding: var(--space-3xl); } page-notifications .empty-icon { font-size: 4rem; margin-bottom: var(--space-md); filter: grayscale(1); } page-notifications .empty-state h3 { margin: 0 0 var(--space-sm); } page-notifications .notification-skeleton { padding: var(--space-md) var(--space-lg); background-color: var(--color-bg); } page-notifications .skeleton-line { height: 14px; background-color: var(--color-bg-tertiary); border-radius: var(--radius-sm); margin-bottom: var(--space-xs); } page-notifications .skeleton-line-short { width: 60%; } @media (max-width: 768px) { page-notifications .notification-delete { opacity: 1; } } ` document.head.appendChild(style)