import { ref } from "vue"; import { defineStore } from "pinia"; import * as api from "@/api/canonicalSystems"; import type { CanonicalSystem, MappingProposal } from "@/api/canonicalSystems"; import { useToastStore } from "@/stores/toast"; import { apiErrorMessage } from "@/api/client"; /** * The global area catalog (milestone 307). Shared by every project, so it is * fetched ONCE per session rather than per project — the whole point of the * table is that it is the same list everywhere. */ export const useCanonicalSystemsStore = defineStore("canonicalSystems", () => { const catalog = ref([]); const loaded = ref(false); const loading = ref(false); const proposalsByProject = ref>({}); async function fetchCatalog(force = false) { if (loaded.value && !force) return catalog.value; loading.value = true; try { catalog.value = await api.listCanonicalSystems(); loaded.value = true; } catch { // A naming aid must never break the screen it rides on — an empty // catalog degrades the suggestion, it does not fail the form. catalog.value = []; } finally { loading.value = false; } return catalog.value; } function byId(id: number | null): CanonicalSystem | undefined { if (id == null) return undefined; return catalog.value.find((c) => c.id === id); } async function fetchProposals(projectId: number) { proposalsByProject.value[projectId] = await api.proposeMappings(projectId); return proposalsByProject.value[projectId]; } /** Apply or clear one mapping, then drop it from the pending proposals. */ async function mapSystem(projectId: number, systemId: number, canonicalId: number | null) { try { await api.mapSystem(systemId, canonicalId); } catch (e) { useToastStore().show(apiErrorMessage(e, "Failed to map system"), "error"); throw e; } dismissProposal(projectId, systemId); } /** Remove a proposal from the pending list without writing anything. */ function dismissProposal(projectId: number, systemId: number) { const list = proposalsByProject.value[projectId]; if (list) { proposalsByProject.value[projectId] = list.filter((p) => p.system_id !== systemId); } } async function createEntry(data: { name: string; description?: string }) { const entry = await api.createCanonicalSystem(data); catalog.value.push(entry); return entry; } async function updateEntry( id: number, data: Partial<{ name: string; description: string; order_index: number }>, ) { const entry = await api.updateCanonicalSystem(id, data); const idx = catalog.value.findIndex((c) => c.id === id); if (idx >= 0) catalog.value[idx] = entry; return entry; } return { catalog, loaded, loading, proposalsByProject, fetchCatalog, byId, fetchProposals, mapSystem, dismissProposal, createEntry, updateEntry, }; });