Files
notely/frontend/src/stores/spaceStore.js
domrichardson b9ca845b9c
All checks were successful
Build and Push App Image / build-and-push (push) Successful in 1m20s
feat: Created task lists that work in categories
2026-03-29 16:14:23 +01:00

421 lines
14 KiB
JavaScript

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,
};
});