diff --git a/src/App.vue b/src/App.vue index 906d8b7..7d2824d 100644 --- a/src/App.vue +++ b/src/App.vue @@ -2,4 +2,5 @@ + \ No newline at end of file diff --git a/src/components.d.ts b/src/components.d.ts index 07643a1..292d2c1 100644 --- a/src/components.d.ts +++ b/src/components.d.ts @@ -30,11 +30,6 @@ declare module 'vue' { RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] Select: typeof import('primevue/select')['default'] - Tab: typeof import('primevue/tab')['default'] - TabList: typeof import('primevue/tablist')['default'] - TabPanel: typeof import('primevue/tabpanel')['default'] - TabPanels: typeof import('primevue/tabpanels')['default'] - Tabs: typeof import('primevue/tabs')['default'] Tag: typeof import('primevue/tag')['default'] Textarea: typeof import('primevue/textarea')['default'] Toast: typeof import('primevue/toast')['default'] diff --git a/src/components/LoadingOverlay.vue b/src/components/LoadingOverlay.vue new file mode 100644 index 0000000..7ecbb90 --- /dev/null +++ b/src/components/LoadingOverlay.vue @@ -0,0 +1,34 @@ + + + + + diff --git a/src/composables/useLoading.ts b/src/composables/useLoading.ts new file mode 100644 index 0000000..234fafa --- /dev/null +++ b/src/composables/useLoading.ts @@ -0,0 +1,22 @@ +import { ref } from 'vue' + +const pendingCount = ref(0) +const loading = ref(false) + +export function useLoading() { + function start() { + pendingCount.value++ + loading.value = true + } + + function stop() { + if (pendingCount.value > 0) { + pendingCount.value-- + } + if (pendingCount.value === 0) { + loading.value = false + } + } + + return { loading, start, stop } +} diff --git a/src/services/api.ts b/src/services/api.ts index 04b0e89..e692913 100644 --- a/src/services/api.ts +++ b/src/services/api.ts @@ -1,4 +1,7 @@ import axios, { type AxiosInstance } from 'axios' +import { useLoading } from '../composables/useLoading' + +const { start: loadingStart, stop: loadingStop } = useLoading() export const api: AxiosInstance = axios.create({ baseURL: import.meta.env.VITE_API_BASE_URL ?? 'http://localhost:2000', @@ -8,6 +11,7 @@ export const api: AxiosInstance = axios.create({ }) api.interceptors.request.use((config) => { + loadingStart() const token = localStorage.getItem('mws_token') if (token) { config.headers.Authorization = `Bearer ${token}` @@ -16,8 +20,12 @@ api.interceptors.request.use((config) => { }) api.interceptors.response.use( - (response) => response, + (response) => { + loadingStop() + return response + }, (error) => { + loadingStop() if (error.response?.status === 401) { localStorage.removeItem('mws_token') localStorage.removeItem('mws_user') diff --git a/src/views/tasks/TasksBoardView.vue b/src/views/tasks/TasksBoardView.vue index 1168c90..ec1f2b5 100644 --- a/src/views/tasks/TasksBoardView.vue +++ b/src/views/tasks/TasksBoardView.vue @@ -29,10 +29,10 @@ draggable="true" @dragstart="onDragStart(task)" @dragend="onDragEnd" - @click.stop="toggleDesc(task.id)" + @click.stop="openEdit(task)" >
{{ task.title }}
-
{{ task.description }}
+
{{ task.description }}
{{ task.assigneeName }} @@ -80,7 +80,7 @@ const route = useRoute() const toast = useToast() const auth = useAuthStore() -const projectId = String(route.params.id) +const projectId = computed(() => String(route.params.id)) const tasks = ref([]) const members = ref<{ userId: string; displayName: string }[]>([]) @@ -89,13 +89,10 @@ const dragOverStatus = ref(null) const dialogVisible = ref(false) const editingTask = ref(null) -const expandedDescs = ref(new Set()) -function toggleDesc(id: string) { - const s = new Set(expandedDescs.value) - if (s.has(id)) s.delete(id) - else s.add(id) - expandedDescs.value = s +function openEdit(task: Task) { + editingTask.value = task + dialogVisible.value = true } const columns = [ @@ -111,7 +108,7 @@ function tasksIn(status: TaskStatus) { async function load() { try { - const res = await getTasks(projectId, undefined, 1, 100) + const res = await getTasks(projectId.value, undefined, 1, 100) tasks.value = res.items } catch (e) { toast.add({ severity: 'error', summary: 'Error', detail: errorMessage(e), life: 4000 }) @@ -120,7 +117,7 @@ async function load() { async function loadMembers() { try { - const res = await getMembers(projectId, 1, 100) + const res = await getMembers(projectId.value, 1, 100) members.value = res.items.map((m) => ({ userId: m.userId, displayName: m.displayName, @@ -196,10 +193,14 @@ function formatDate(v: string) { return new Date(v).toLocaleDateString() } -onMounted(async () => { - await loadMembers() - await load() -}) +watch( + () => route.params.id, + async () => { + await loadMembers() + await load() + }, + { immediate: true }, +)