// static/vendor/js/notifications.js /** * Vendor notifications center page logic * View and manage notifications */ const vendorNotificationsLog = window.LogConfig.loggers.vendorNotifications || window.LogConfig.createLogger('vendorNotifications', false); vendorNotificationsLog.info('Loading...'); function vendorNotifications() { vendorNotificationsLog.info('vendorNotifications() called'); return { // Inherit base layout state ...data(), // Set page identifier currentPage: 'notifications', // Loading states loading: true, error: '', loadingNotifications: false, // Notifications data notifications: [], stats: { total: 0, unread_count: 0 }, // Pagination page: 1, limit: 20, skip: 0, // Filters filters: { priority: '', is_read: '' }, // Settings settings: null, showSettingsModal: false, settingsForm: { email_notifications: true, in_app_notifications: true }, async init() { vendorNotificationsLog.info('Notifications init() called'); // Guard against multiple initialization if (window._vendorNotificationsInitialized) { vendorNotificationsLog.warn('Already initialized, skipping'); return; } window._vendorNotificationsInitialized = true; try { await this.loadNotifications(); } catch (error) { vendorNotificationsLog.error('Init failed:', error); this.error = 'Failed to initialize notifications page'; } finally { this.loading = false; } vendorNotificationsLog.info('Notifications initialization complete'); }, /** * Load notifications with current filters */ async loadNotifications() { this.loadingNotifications = true; this.error = ''; try { this.skip = (this.page - 1) * this.limit; const params = new URLSearchParams(); params.append('skip', this.skip); params.append('limit', this.limit); if (this.filters.is_read === 'false') { params.append('unread_only', 'true'); } const response = await apiClient.get(`/vendor/${this.vendorCode}/notifications?${params}`); this.notifications = response.notifications || []; this.stats.total = response.total || 0; this.stats.unread_count = response.unread_count || 0; vendorNotificationsLog.info(`Loaded ${this.notifications.length} notifications`); } catch (error) { vendorNotificationsLog.error('Failed to load notifications:', error); this.error = error.message || 'Failed to load notifications'; } finally { this.loadingNotifications = false; } }, /** * Mark notification as read */ async markAsRead(notification) { try { await apiClient.put(`/vendor/${this.vendorCode}/notifications/${notification.id}/read`); // Update local state notification.is_read = true; this.stats.unread_count = Math.max(0, this.stats.unread_count - 1); Utils.showToast('Notification marked as read', 'success'); } catch (error) { vendorNotificationsLog.error('Failed to mark as read:', error); Utils.showToast(error.message || 'Failed to mark notification as read', 'error'); } }, /** * Mark all notifications as read */ async markAllAsRead() { try { await apiClient.put(`/vendor/${this.vendorCode}/notifications/mark-all-read`); // Update local state this.notifications.forEach(n => n.is_read = true); this.stats.unread_count = 0; Utils.showToast('All notifications marked as read', 'success'); } catch (error) { vendorNotificationsLog.error('Failed to mark all as read:', error); Utils.showToast(error.message || 'Failed to mark all as read', 'error'); } }, /** * Delete notification */ async deleteNotification(notificationId) { if (!confirm('Are you sure you want to delete this notification?')) { return; } try { await apiClient.delete(`/vendor/${this.vendorCode}/notifications/${notificationId}`); // Remove from local state const wasUnread = this.notifications.find(n => n.id === notificationId && !n.is_read); this.notifications = this.notifications.filter(n => n.id !== notificationId); this.stats.total = Math.max(0, this.stats.total - 1); if (wasUnread) { this.stats.unread_count = Math.max(0, this.stats.unread_count - 1); } Utils.showToast('Notification deleted', 'success'); } catch (error) { vendorNotificationsLog.error('Failed to delete notification:', error); Utils.showToast(error.message || 'Failed to delete notification', 'error'); } }, /** * Open settings modal */ async openSettingsModal() { try { const response = await apiClient.get(`/vendor/${this.vendorCode}/notifications/settings`); this.settingsForm = { email_notifications: response.email_notifications !== false, in_app_notifications: response.in_app_notifications !== false }; this.showSettingsModal = true; } catch (error) { vendorNotificationsLog.error('Failed to load settings:', error); Utils.showToast(error.message || 'Failed to load notification settings', 'error'); } }, /** * Save notification settings */ async saveSettings() { try { await apiClient.put(`/vendor/${this.vendorCode}/notifications/settings`, this.settingsForm); Utils.showToast('Notification settings saved', 'success'); this.showSettingsModal = false; } catch (error) { vendorNotificationsLog.error('Failed to save settings:', error); Utils.showToast(error.message || 'Failed to save settings', 'error'); } }, /** * Get notification icon based on type */ getNotificationIcon(type) { const icons = { 'order_received': 'shopping-cart', 'order_shipped': 'truck', 'order_delivered': 'check-circle', 'low_stock': 'exclamation-triangle', 'import_complete': 'cloud-download', 'import_failed': 'x-circle', 'team_invite': 'user-plus', 'payment_received': 'credit-card', 'system': 'cog' }; return icons[type] || 'bell'; }, /** * Get priority color class */ getPriorityClass(priority) { const classes = { 'critical': 'bg-red-100 text-red-600 dark:bg-red-900 dark:text-red-300', 'high': 'bg-orange-100 text-orange-600 dark:bg-orange-900 dark:text-orange-300', 'normal': 'bg-blue-100 text-blue-600 dark:bg-blue-900 dark:text-blue-300', 'low': 'bg-gray-100 text-gray-600 dark:bg-gray-700 dark:text-gray-300' }; return classes[priority] || classes['normal']; }, /** * Format date for display */ formatDate(dateString) { if (!dateString) return '-'; const date = new Date(dateString); const now = new Date(); const diff = Math.floor((now - date) / 1000); // Show relative time for recent dates if (diff < 60) return 'Just now'; if (diff < 3600) return `${Math.floor(diff / 60)}m ago`; if (diff < 86400) return `${Math.floor(diff / 3600)}h ago`; if (diff < 172800) return 'Yesterday'; // Show full date for older dates return date.toLocaleDateString(); }, // Pagination methods get totalPages() { return Math.ceil(this.stats.total / this.limit); }, prevPage() { if (this.page > 1) { this.page--; this.loadNotifications(); } }, nextPage() { if (this.page < this.totalPages) { this.page++; this.loadNotifications(); } }, goToPage(pageNum) { this.page = pageNum; this.loadNotifications(); } }; }