import { defineStore } from "pinia"; import { ref } from "vue"; import apiClient from "../services/apiClient"; export const useSpaceStore = defineStore("space", () => { const spaces = ref([]); const currentSpace = ref(null); const notes = ref([]); const searchResults = ref([]); const notesSkip = ref(0); const notesLimit = ref(20); const notesHasMore = ref(true); const notesLoading = ref(false); const categories = ref([]); const categoryTree = ref([]); const taskLists = ref([]); const tasks = ref([]); const taskStatuses = ref([]); const noteLinkedTasks = ref([]); const refreshSpaceData = async (spaceId) => { await Promise.all([fetchCategories(spaceId), fetchNotes(spaceId), fetchTaskLists(spaceId), fetchTaskStatuses(spaceId), fetchTasks(spaceId)]); }; const fetchSpaces = async () => { try { const response = await apiClient.get("/api/v1/spaces"); spaces.value = response.data || []; } catch (error) { console.error("Error fetching spaces:", error); } }; const selectSpace = async (spaceId) => { try { const response = await apiClient.get(`/api/v1/spaces/${spaceId}`); currentSpace.value = response.data; await refreshSpaceData(spaceId); } catch (error) { console.error("Error selecting space:", error); } }; const fetchCategories = async (spaceId) => { try { const response = await apiClient.get(`/api/v1/spaces/${spaceId}/categories`); categoryTree.value = response.data || []; categories.value = categoryTree.value; } catch (error) { console.error("Error fetching categories:", error); categoryTree.value = []; categories.value = []; } }; const fetchNotes = async (spaceId, options = {}) => { const { reset = true, limit = notesLimit.value } = options; if (!spaceId) { return; } if (notesLoading.value) { return; } if (!reset && !notesHasMore.value) { return; } if (reset) { notesSkip.value = 0; notesHasMore.value = true; notesLimit.value = limit; } try { notesLoading.value = true; const response = await apiClient.get(`/api/v1/spaces/${spaceId}/notes`, { params: { skip: notesSkip.value, limit, }, }); const fetchedNotes = response.data || []; if (reset) { notes.value = fetchedNotes; } else { notes.value = [...notes.value, ...fetchedNotes]; } notesSkip.value += fetchedNotes.length; notesHasMore.value = fetchedNotes.length === limit; } catch (error) { console.error("Error fetching notes:", error); } finally { notesLoading.value = false; } }; const loadMoreNotes = async (spaceId) => { await fetchNotes(spaceId, { reset: false, limit: notesLimit.value }); }; const createSpace = async (spaceData) => { try { const response = await apiClient.post("/api/v1/spaces", spaceData); spaces.value.push(response.data); currentSpace.value = response.data; localStorage.setItem("currentSpaceId", response.data.id); await refreshSpaceData(response.data.id); return response.data; } catch (error) { throw error.response?.data?.message || error.message; } }; const updateSpace = async (spaceId, spaceData) => { try { const response = await apiClient.put(`/api/v1/spaces/${spaceId}`, spaceData); const index = spaces.value.findIndex((s) => s.id === spaceId); if (index !== -1) { spaces.value[index] = response.data; } if (currentSpace.value?.id === spaceId) { currentSpace.value = response.data; } return response.data; } catch (error) { throw error.response?.data?.message || error.message; } }; const createCategory = async (spaceId, categoryData) => { try { const response = await apiClient.post(`/api/v1/spaces/${spaceId}/categories`, categoryData); await fetchCategories(spaceId); return response.data; } catch (error) { throw error.response?.data?.message || error.message; } }; const updateCategory = async (spaceId, categoryId, categoryData) => { try { const response = await apiClient.put(`/api/v1/spaces/${spaceId}/categories/${categoryId}`, categoryData); await fetchCategories(spaceId); return response.data; } catch (error) { throw error.response?.data?.message || error.message; } }; const deleteCategory = async (spaceId, categoryId) => { try { await apiClient.delete(`/api/v1/spaces/${spaceId}/categories/${categoryId}`); await refreshSpaceData(spaceId); } catch (error) { throw error.response?.data?.message || error.message; } }; const createNote = async (spaceId, noteData) => { try { const response = await apiClient.post(`/api/v1/spaces/${spaceId}/notes`, noteData); await refreshSpaceData(spaceId); return response.data; } catch (error) { throw error.response?.data?.message || error.message; } }; const updateNote = async (spaceId, noteData) => { try { const response = await apiClient.put(`/api/v1/spaces/${spaceId}/notes/${noteData.id}`, noteData); const index = notes.value.findIndex((n) => n.id === noteData.id); if (index !== -1) { notes.value[index] = response.data; } await fetchCategories(spaceId); return response.data; } catch (error) { throw error.response?.data?.message || error.message; } }; const deleteNote = async (spaceId, noteId) => { try { await apiClient.delete(`/api/v1/spaces/${spaceId}/notes/${noteId}`); notes.value = notes.value.filter((n) => n.id !== noteId); await fetchCategories(spaceId); } catch (error) { throw error.response?.data?.message || error.message; } }; const searchNotes = async (query) => { if (!currentSpace.value?.id) { searchResults.value = []; return []; } try { const response = await apiClient.get(`/api/v1/spaces/${currentSpace.value.id}/notes/search`, { params: { q: query } }); searchResults.value = response.data || []; return searchResults.value; } catch (error) { console.error("Error searching notes:", error); searchResults.value = []; return []; } }; const clearSearchResults = () => { searchResults.value = []; }; const fetchTaskStatuses = async (spaceId) => { if (!spaceId) { taskStatuses.value = []; return []; } try { const response = await apiClient.get(`/api/v1/spaces/${spaceId}/task-statuses`); taskStatuses.value = response.data || []; return taskStatuses.value; } catch (error) { console.error("Error fetching task statuses:", error); taskStatuses.value = []; return []; } }; const fetchTaskLists = async (spaceId) => { if (!spaceId) { taskLists.value = []; return []; } try { const response = await apiClient.get(`/api/v1/spaces/${spaceId}/task-lists`); taskLists.value = response.data || []; return taskLists.value; } catch (error) { console.error("Error fetching task lists:", error); taskLists.value = []; return []; } }; const createTaskList = async (spaceId, payload) => { const response = await apiClient.post(`/api/v1/spaces/${spaceId}/task-lists`, payload); await fetchTaskLists(spaceId); return response.data; }; const updateTaskList = async (spaceId, taskListId, payload) => { const response = await apiClient.put(`/api/v1/spaces/${spaceId}/task-lists/${taskListId}`, payload); await fetchTaskLists(spaceId); return response.data; }; const deleteTaskList = async (spaceId, taskListId) => { await apiClient.delete(`/api/v1/spaces/${spaceId}/task-lists/${taskListId}`); await fetchTaskLists(spaceId); }; const createTaskStatus = async (spaceId, payload) => { const response = await apiClient.post(`/api/v1/spaces/${spaceId}/task-statuses`, payload); await fetchTaskStatuses(spaceId); return response.data; }; const updateTaskStatus = async (spaceId, statusId, payload) => { const response = await apiClient.put(`/api/v1/spaces/${spaceId}/task-statuses/${statusId}`, payload); await fetchTaskStatuses(spaceId); return response.data; }; const deleteTaskStatus = async (spaceId, statusId) => { await apiClient.delete(`/api/v1/spaces/${spaceId}/task-statuses/${statusId}`); await fetchTaskStatuses(spaceId); }; const reorderTaskStatuses = async (spaceId, orderedStatusIds) => { const response = await apiClient.put(`/api/v1/spaces/${spaceId}/task-statuses/reorder`, { ordered_status_ids: orderedStatusIds, }); taskStatuses.value = response.data || []; return taskStatuses.value; }; const fetchTasks = async (spaceId, filters = {}) => { if (!spaceId) { tasks.value = []; return []; } const params = {}; if (filters.taskListId) { params.taskListId = filters.taskListId; } if (filters.statusId) { params.statusId = filters.statusId; } if (typeof filters.parentTaskId === "string") { params.parentTaskId = filters.parentTaskId; } try { const response = await apiClient.get(`/api/v1/spaces/${spaceId}/tasks`, { params }); tasks.value = response.data || []; return tasks.value; } catch (error) { console.error("Error fetching tasks:", error); tasks.value = []; return []; } }; const searchTasks = async (spaceId, query) => { if (!spaceId || !query?.trim()) { return []; } const response = await apiClient.get(`/api/v1/spaces/${spaceId}/tasks/search`, { params: { q: query } }); return response.data || []; }; const getTask = async (spaceId, taskId) => { const response = await apiClient.get(`/api/v1/spaces/${spaceId}/tasks/${taskId}`); return response.data; }; const createTask = async (spaceId, payload) => { const response = await apiClient.post(`/api/v1/spaces/${spaceId}/tasks`, payload); await fetchTasks(spaceId); return response.data; }; const updateTask = async (spaceId, taskId, payload) => { const response = await apiClient.put(`/api/v1/spaces/${spaceId}/tasks/${taskId}`, payload); await fetchTasks(spaceId); return response.data; }; const deleteTask = async (spaceId, taskId) => { await apiClient.delete(`/api/v1/spaces/${spaceId}/tasks/${taskId}`); await fetchTasks(spaceId); }; const transitionTask = async (spaceId, taskId, direction) => { const response = await apiClient.post(`/api/v1/spaces/${spaceId}/tasks/${taskId}/transition`, { direction }); await fetchTasks(spaceId); return response.data; }; const fetchTasksForNote = async (spaceId, noteId) => { if (!spaceId || !noteId) { noteLinkedTasks.value = []; return []; } const response = await apiClient.get(`/api/v1/spaces/${spaceId}/notes/${noteId}/tasks`); noteLinkedTasks.value = response.data || []; return noteLinkedTasks.value; }; const linkTaskToNote = async (spaceId, taskId, noteId) => { const response = await apiClient.post(`/api/v1/spaces/${spaceId}/tasks/${taskId}/notes`, { note_id: noteId }); return response.data; }; const unlinkTaskFromNote = async (spaceId, taskId, noteId) => { const response = await apiClient.delete(`/api/v1/spaces/${spaceId}/tasks/${taskId}/notes/${noteId}`); return response.data; }; return { spaces, currentSpace, notes, searchResults, notesHasMore, notesLoading, categories, categoryTree, taskLists, tasks, taskStatuses, noteLinkedTasks, fetchSpaces, selectSpace, fetchNotes, loadMoreNotes, fetchCategories, createSpace, updateSpace, createCategory, updateCategory, deleteCategory, createNote, updateNote, deleteNote, searchNotes, clearSearchResults, fetchTaskStatuses, fetchTaskLists, createTaskList, updateTaskList, deleteTaskList, createTaskStatus, updateTaskStatus, deleteTaskStatus, reorderTaskStatuses, fetchTasks, searchTasks, getTask, createTask, updateTask, deleteTask, transitionTask, fetchTasksForNote, linkTaskToNote, unlinkTaskFromNote, }; });