import { defineStore } from 'pinia'; import { serviceService } from '@/services/serviceService'; import { ServiceModel } from '@/models/service'; import type { Service } from '@/models/service'; export const useServicesStore = defineStore('jmapc_services', { state: () => ({ services: [] as ServiceModel[], loading: false, error: null as string | null, }), getters: { /** * Get services filtered by capability */ byCapability: (state) => (capability: string) => { return state.services.filter(s => s.capabilities.includes(capability)); }, /** * Get mail services */ mailServices: (state) => { return state.services.filter(s => s.hasMail()); }, /** * Get contact services */ contactServices: (state) => { return state.services.filter(s => s.hasContacts()); }, /** * Get calendar services */ calendarServices: (state) => { return state.services.filter(s => s.hasCalendars()); }, /** * Get service by ID */ getById: (state) => (id: string) => { return state.services.find(s => s.id === id); }, }, actions: { /** * Load all services from API */ async loadServices(capability?: string) { this.loading = true; this.error = null; try { const response = await serviceService.list(capability); this.services = response.services.map(s => new ServiceModel(s)); } catch (error: any) { this.error = error.message || 'Failed to load services'; throw error; } finally { this.loading = false; } }, /** * Load a single service */ async loadService(id: string) { this.loading = true; this.error = null; try { const service = await serviceService.fetch(id); const model = new ServiceModel(service); // Update or add to store const index = this.services.findIndex(s => s.id === id); if (index >= 0) { this.services[index] = model; } else { this.services.push(model); } return model; } catch (error: any) { this.error = error.message || 'Failed to load service'; throw error; } finally { this.loading = false; } }, /** * Create a new service */ async createService(service: Partial) { this.loading = true; this.error = null; try { const created = await serviceService.create(service); const model = new ServiceModel(created); this.services.push(model); return model; } catch (error: any) { this.error = error.message || 'Failed to create service'; throw error; } finally { this.loading = false; } }, /** * Update an existing service */ async updateService(id: string, service: Partial) { this.loading = true; this.error = null; try { const updated = await serviceService.update(id, service); const model = new ServiceModel(updated); const index = this.services.findIndex(s => s.id === id); if (index >= 0) { this.services[index] = model; } return model; } catch (error: any) { this.error = error.message || 'Failed to update service'; throw error; } finally { this.loading = false; } }, /** * Delete a service */ async deleteService(id: string) { this.loading = true; this.error = null; try { await serviceService.destroy(id); this.services = this.services.filter(s => s.id !== id); } catch (error: any) { this.error = error.message || 'Failed to delete service'; throw error; } finally { this.loading = false; } }, /** * Test connection with provided settings */ async testConnection(config: any) { return serviceService.test(config); }, /** * Auto-discover JMAP endpoint */ async discover(hostname: string, protocol?: string, port?: number, path?: string) { return serviceService.discover(hostname, protocol, port, path); }, /** * Fetch collections for a service */ async fetchCollections(id: string) { return serviceService.fetchCollections(id); }, /** * Refresh collections for a service */ async refreshCollections(id: string) { const result = await serviceService.refreshCollections(id); // Update local service with fresh collection data const service = this.getById(id); if (service && result.success) { service.collections = { contacts: result.contacts || [], calendars: result.calendars || [] }; } return result; }, /** * Clear all services */ reset() { this.services = []; this.error = null; this.loading = false; }, }, });