import { defineStore } from "pinia";
import { areasApi } from "../api/modules/areas";
function buildAreaTree(areas) {
const map = {};
const roots = [];
for (const area of areas) {
map[area.id] = { ...area, children: [] };
}
for (const area of areas) {
const node = map[area.id];
const isSelfReference = area.parent_id && area.parent_id == area.id;
const parentExists = area.parent_id && map[area.parent_id];
if (!isSelfReference && parentExists) {
map[area.parent_id].children.push(node);
} else {
roots.push(node);
}
}
if (roots.length === 0 && areas.length > 0) {
return Object.values(map);
}
return roots;
}
export const useAreasStore = defineStore("areas", {
state: () => ({
areas: [],
isLoading: false,
error: null,
_listAbortController: null,
currentArea: null,
currentAreaDevices: [],
currentAreaScripts: [],
isLoadingAreaDetail: false,
errorAreaDetail: null,
_areaDetailAbortController: null,
}),
getters: {
areasById(state) {
return Object.fromEntries(state.areas.map((area) => [String(area.id), area]));
},
areaTree(state) {
return buildAreaTree(state.areas);
},
},
actions: {
async loadAreas() {
this._listAbortController?.abort();
const controller = new AbortController();
this._listAbortController = controller;
this.isLoading = true;
this.error = null;
const result = await areasApi.list({ signal: controller.signal });
this._listAbortController = null;
this.isLoading = false;
if (!result.ok) {
if (result.error?.type === "timeout") {
return result;
}
this.error = result.error;
return result;
}
this.areas = result.data?.data?.areas || [];
return result;
},
async loadAreaDetail(areaId) {
this._areaDetailAbortController?.abort();
const controller = new AbortController();
this._areaDetailAbortController = controller;
this.isLoadingAreaDetail = true;
this.errorAreaDetail = null;
this.currentArea = this.areasById[String(areaId)] || null;
this.currentAreaDevices = [];
this.currentAreaScripts = [];
const [devicesResult, scriptsResult] = await Promise.all([
areasApi.devices(areaId, { signal: controller.signal }),
areasApi.scripts(areaId, { signal: controller.signal }),
]);
this._areaDetailAbortController = null;
this.isLoadingAreaDetail = false;
if (!devicesResult.ok) {
if (devicesResult.error?.type !== "timeout") {
this.errorAreaDetail = devicesResult.error;
}
return { ok: false, error: this.errorAreaDetail };
}
if (!scriptsResult.ok) {
if (scriptsResult.error?.type !== "timeout") {
this.errorAreaDetail = scriptsResult.error;
}
return { ok: false, error: this.errorAreaDetail };
}
this.currentAreaDevices = devicesResult.data?.data?.devices || [];
this.currentAreaScripts = scriptsResult.data?.data?.scripts || [];
return { ok: true };
},
clearAreaDetail() {
this.currentArea = null;
this.currentAreaDevices = [];
this.currentAreaScripts = [];
this.errorAreaDetail = null;
this._areaDetailAbortController?.abort();
this._areaDetailAbortController = null;
},
async loadAreaDevices(areaId) {
const result = await areasApi.devices(areaId);
if (result.ok) {
this.currentAreaDevices = result.data?.data?.devices || [];
}
return result;
},
async loadAreaScripts(areaId) {
const result = await areasApi.scripts(areaId);
if (result.ok) {
this.currentAreaScripts = result.data?.data?.scripts || [];
}
return result;
},
async createArea(payload) {
const result = await areasApi.newArea(payload);
if (result.ok) {
const newArea = result.data?.data?.area;
if (newArea) {
this.areas.push(newArea);
}
}
return result;
},
async renameArea(areaId, displayName) {
const result = await areasApi.updateDisplayName({ area_id: areaId, display_name: displayName });
if (result.ok) {
const idx = this.areas.findIndex((a) => a.id === areaId);
if (idx !== -1) {
this.areas[idx] = { ...this.areas[idx], display_name: displayName };
}
}
return result;
},
async removeArea(areaId) {
const result = await areasApi.remove(areaId);
if (result.ok) {
this.areas = this.areas.filter((a) => a.id !== areaId);
}
return result;
},
async assignToArea(areaId, parentAreaId) {
const result = await areasApi.placeInArea({ target_id: areaId, place_in_area_id: parentAreaId });
if (result.ok) {
const idx = this.areas.findIndex((a) => a.id === areaId);
if (idx !== -1) {
this.areas.splice(idx, 1, { ...this.areas[idx], parent_id: Number(parentAreaId) });
}
}
return result;
},
async unassignArea(areaId) {
const result = await areasApi.unassign(areaId);
if (result.ok) {
const idx = this.areas.findIndex((a) => a.id === areaId);
if (idx !== -1) {
this.areas.splice(idx, 1, { ...this.areas[idx], parent_id: 0 });
}
}
return result;
},
},
});