// noqa: js-006 - async init pattern is safe, loadData has try/catch // static/admin/js/subscriptions.js // noqa: JS-003 - Uses ...baseData which is data() with safety check const subsLog = window.LogConfig?.loggers?.subscriptions || console; function adminSubscriptions() { // Get base data with safety check for standalone usage const baseData = typeof data === 'function' ? data() : {}; return { // Inherit base layout functionality from init-alpine.js ...baseData, // Page-specific state currentPage: 'subscriptions', loading: true, error: null, successMessage: null, saving: false, // Data subscriptions: [], stats: null, // Filters filters: { search: '', status: '', tier: '' }, // Pagination pagination: { page: 1, per_page: 20, total: 0, pages: 0 }, // Sorting sortBy: 'vendor_name', sortOrder: 'asc', // Modal state showModal: false, editingSub: null, formData: { tier: '', status: '', custom_orders_limit: null, custom_products_limit: null, custom_team_limit: null }, // Computed: Total pages get totalPages() { return this.pagination.pages; }, // Computed: Start index for pagination display get startIndex() { if (this.pagination.total === 0) return 0; return (this.pagination.page - 1) * this.pagination.per_page + 1; }, // Computed: End index for pagination display get endIndex() { const end = this.pagination.page * this.pagination.per_page; return end > this.pagination.total ? this.pagination.total : end; }, // Computed: Page numbers for pagination get pageNumbers() { const pages = []; const totalPages = this.totalPages; const current = this.pagination.page; if (totalPages <= 7) { for (let i = 1; i <= totalPages; i++) { pages.push(i); } } else { pages.push(1); if (current > 3) { pages.push('...'); } const start = Math.max(2, current - 1); const end = Math.min(totalPages - 1, current + 1); for (let i = start; i <= end; i++) { pages.push(i); } if (current < totalPages - 2) { pages.push('...'); } pages.push(totalPages); } return pages; }, async init() { // Guard against multiple initialization if (window._adminSubscriptionsInitialized) { subsLog.warn('Already initialized, skipping'); return; } window._adminSubscriptionsInitialized = true; subsLog.info('=== SUBSCRIPTIONS PAGE INITIALIZING ==='); // Load platform settings for rows per page if (window.PlatformSettings) { this.pagination.per_page = await window.PlatformSettings.getRowsPerPage(); } await this.loadStats(); await this.loadSubscriptions(); }, async refresh() { this.error = null; this.successMessage = null; await this.loadStats(); await this.loadSubscriptions(); }, async loadStats() { try { const data = await apiClient.get('/admin/subscriptions/stats'); this.stats = data; subsLog.info('Loaded subscription stats'); } catch (error) { subsLog.error('Failed to load stats:', error); } }, async loadSubscriptions() { this.loading = true; this.error = null; try { const params = new URLSearchParams(); params.append('page', this.pagination.page); params.append('per_page', this.pagination.per_page); if (this.filters.status) params.append('status', this.filters.status); if (this.filters.tier) params.append('tier', this.filters.tier); if (this.filters.search) params.append('search', this.filters.search); if (this.sortBy) params.append('sort_by', this.sortBy); if (this.sortOrder) params.append('sort_order', this.sortOrder); const data = await apiClient.get(`/admin/subscriptions?${params}`); this.subscriptions = data.subscriptions || []; this.pagination.total = data.total; this.pagination.pages = data.pages; subsLog.info(`Loaded ${this.subscriptions.length} subscriptions (total: ${this.pagination.total})`); } catch (error) { subsLog.error('Failed to load subscriptions:', error); this.error = error.message || 'Failed to load subscriptions'; } finally { this.loading = false; } }, resetFilters() { this.filters = { search: '', status: '', tier: '' }; this.pagination.page = 1; this.loadSubscriptions(); }, handleSort(key) { if (this.sortBy === key) { this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc'; } else { this.sortBy = key; this.sortOrder = 'asc'; } this.pagination.page = 1; this.loadSubscriptions(); }, previousPage() { if (this.pagination.page > 1) { this.pagination.page--; this.loadSubscriptions(); } }, nextPage() { if (this.pagination.page < this.totalPages) { this.pagination.page++; this.loadSubscriptions(); } }, goToPage(pageNum) { if (pageNum !== '...' && pageNum >= 1 && pageNum <= this.totalPages) { this.pagination.page = pageNum; this.loadSubscriptions(); } }, openEditModal(sub) { this.editingSub = sub; this.formData = { tier: sub.tier, status: sub.status, custom_orders_limit: sub.custom_orders_limit, custom_products_limit: sub.custom_products_limit, custom_team_limit: sub.custom_team_limit }; this.showModal = true; }, closeModal() { this.showModal = false; this.editingSub = null; }, async saveSubscription() { if (!this.editingSub) return; this.saving = true; this.error = null; try { // Clean up null values for empty strings const payload = { ...this.formData }; if (payload.custom_orders_limit === '') payload.custom_orders_limit = null; if (payload.custom_products_limit === '') payload.custom_products_limit = null; if (payload.custom_team_limit === '') payload.custom_team_limit = null; await apiClient.patch(`/admin/subscriptions/${this.editingSub.vendor_id}`, payload); this.successMessage = `Subscription for "${this.editingSub.vendor_name}" updated`; this.closeModal(); await this.loadSubscriptions(); await this.loadStats(); } catch (error) { subsLog.error('Failed to save subscription:', error); this.error = error.message || 'Failed to update subscription'; } finally { this.saving = false; } }, formatDate(dateStr) { if (!dateStr) return '-'; return new Date(dateStr).toLocaleDateString('de-LU', { year: 'numeric', month: 'short', day: 'numeric' }); }, formatCurrency(cents) { if (cents === null || cents === undefined) return '-'; return new Intl.NumberFormat('de-LU', { style: 'currency', currency: 'EUR' }).format(cents / 100); } }; } subsLog.info('Subscriptions module loaded');