import { defineStore } from 'pinia'; import type { IntegrationPointType, IntegrationPoint, IntegrationEntry, IntegrationItem, IntegrationGroup } from '@KTXC/types/integrationTypes'; export const useIntegrationStore = defineStore('integrationStore', { state: () => ({ points: new Map(), }), actions: { // Ensure an integration point exists ensurePoint(pointType: IntegrationPointType): void { if (!this.points.has(pointType)) { this.points.set(pointType, { items: new Map() }); } }, // Register a single item to an integration point registerItem(pointType: IntegrationPointType, item: IntegrationItem): void { this.ensurePoint(pointType); const point = this.points.get(pointType)!; point.items.set(item.id, item); }, // Register a group to an integration point registerGroup(pointType: IntegrationPointType, group: IntegrationGroup): void { this.ensurePoint(pointType); const point = this.points.get(pointType)!; point.items.set(group.id, group); }, // Bulk register from module integrations registerModuleIntegrations( moduleHandle: string, integrations: Record ): void { for (const [pointType, entries] of Object.entries(integrations)) { if (!entries || !Array.isArray(entries)) continue; entries.forEach((entry: any) => { const prefixedEntry = this.prefixEntry(moduleHandle, entry); if (entry.type === 'group' || ('items' in entry && Array.isArray(entry.items))) { this.registerGroup(pointType as IntegrationPointType, prefixedEntry as IntegrationGroup); } else { this.registerItem(pointType as IntegrationPointType, prefixedEntry as IntegrationItem); } }); } }, // Prefix IDs and paths with module handle prefixEntry(moduleHandle: string, entry: any): IntegrationEntry { const prefixed: any = { ...entry, id: entry.id ? `${moduleHandle}.${entry.id}` : `${moduleHandle}.${this.randomID()}`, moduleHandle, }; // Remove 'type' field as it's only used for module-side disambiguation delete prefixed.type; // Prefix localization keys with the module namespace if (entry.l10n) { prefixed.l10n = `${moduleHandle}.${entry.l10n}`; } // Prefix internal paths if (entry.path) { prefixed.to = `/m/${moduleHandle}${entry.path}`; delete prefixed.path; } else if (entry.to && entry.toType !== 'external') { prefixed.to = `/m/${moduleHandle}${entry.to}`; } // Recursively prefix items in groups if (entry.items && Array.isArray(entry.items)) { prefixed.items = entry.items.map((item: any) => this.prefixEntry(moduleHandle, item)); } return prefixed; }, // Update a specific item (useful for badges, visibility, etc.) updateItem( pointType: IntegrationPointType, itemId: string, updates: Partial ): void { const point = this.points.get(pointType); if (!point) return; const item = point.items.get(itemId); if (item && !('items' in item)) { point.items.set(itemId, { ...item, ...updates }); } }, // Update badge for notification icons updateBadge( pointType: IntegrationPointType, itemId: string, badge: string | number | null, badgeColor?: string ): void { this.updateItem(pointType, itemId, { badge, badgeColor }); }, // Toggle visibility setVisibility( pointType: IntegrationPointType, itemId: string, visible: boolean ): void { this.updateItem(pointType, itemId, { visible }); }, // Remove an item unregisterItem(pointType: IntegrationPointType, itemId: string): void { const point = this.points.get(pointType); if (point) { point.items.delete(itemId); } }, // Remove all items from a module unregisterModule(moduleHandle: string): void { this.points.forEach((point) => { point.items.forEach((entry, id) => { if (entry.moduleHandle === moduleHandle) { point.items.delete(id); } }); }); }, reset(): void { this.points.clear(); }, randomID(length = 8): string { return Math.random().toString(36).substring(2, 2 + length); }, }, getters: { // Get all entries for an integration point, sorted by priority getPoint: (state) => (pointType: IntegrationPointType): IntegrationEntry[] => { const point = state.points.get(pointType); if (!point) return []; return Array.from(point.items.values()) .filter(entry => entry.visible !== false) .sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100)); }, // Get items only (no groups) getItems: (state) => (pointType: IntegrationPointType): IntegrationItem[] => { const point = state.points.get(pointType); if (!point) return []; return Array.from(point.items.values()) .filter((entry): entry is IntegrationItem => !('items' in entry) && entry.visible !== false) .sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100)); }, // Get groups only getGroups: (state) => (pointType: IntegrationPointType): IntegrationGroup[] => { const point = state.points.get(pointType); if (!point) return []; return Array.from(point.items.values()) .filter((entry): entry is IntegrationGroup => 'items' in entry && entry.visible !== false) .sort((a, b) => (a.priority ?? 100) - (b.priority ?? 100)); }, // Get a specific item by ID getItemById: (state) => (pointType: IntegrationPointType, itemId: string): IntegrationEntry | undefined => { const point = state.points.get(pointType); return point?.items.get(itemId); }, }, });