diff --git a/src/composables/useKanbanDragAndDrop.ts b/src/composables/useKanbanDragAndDrop.ts index ea825ba..e08a2cd 100644 --- a/src/composables/useKanbanDragAndDrop.ts +++ b/src/composables/useKanbanDragAndDrop.ts @@ -84,12 +84,19 @@ export function useKanbanDragAndDrop(statusSchema: Record) { if (currentCat === 'complete') currentCat = 'done'; if (currentCat !== targetStatus) { - const possibleStatuses = statusSchema[targetStatus]; - const statusName: string = (possibleStatuses && possibleStatuses.length > 0) - ? (possibleStatuses[0] as string) - : (targetStatus === 'inProgress' ? 'In Progress' : targetStatus === 'todo' ? 'To Do' : 'Done'); - - dashboardStore.updateTaskStatus(task.key, { status: statusName }); + if (dashboardStore.activeSource === 'trello') { + // Trello cards are moved by list ID, not by status name + const listId = dashboardStore.trelloListIds[targetStatus]; + if (listId) { + dashboardStore.moveTrelloCard(task.key, listId); + } + } else { + const possibleStatuses = statusSchema[targetStatus]; + const statusName: string = (possibleStatuses && possibleStatuses.length > 0) + ? (possibleStatuses[0] as string) + : (targetStatus === 'inProgress' ? 'In Progress' : targetStatus === 'todo' ? 'To Do' : 'Done'); + dashboardStore.updateTaskStatus(task.key, { status: statusName }); + } } } draggedTask.value = null; diff --git a/src/stores/dashboard.ts b/src/stores/dashboard.ts index f2e6ae3..98a6f22 100644 --- a/src/stores/dashboard.ts +++ b/src/stores/dashboard.ts @@ -67,6 +67,8 @@ export const useDashboardStore = defineStore('dashboard', () => { const activeSource = ref<'jira' | 'trello'>('jira'); const trelloBoards = ref<{ id: string; name: string }[]>([]); const selectedTrelloBoardId = ref(null); + // Maps status category → first Trello list ID (used for card moves via drag-and-drop) + const trelloListIds = ref>({}); // Auto-select first project when projects load but nothing is selected watch(projects, (newProjects) => { @@ -533,7 +535,11 @@ export const useDashboardStore = defineStore('dashboard', () => { try { const res = await apiClient.get('/api/trello/boards'); trelloBoards.value = res.data.boards || []; - if (!selectedTrelloBoardId.value && trelloBoards.value.length > 0) { + // Restore server-persisted board selection (mirrors Jira project selection) + const persistedId: string | null = res.data.selected_board_id ?? null; + if (persistedId && trelloBoards.value.find(b => b.id === persistedId)) { + selectedTrelloBoardId.value = persistedId; + } else if (!selectedTrelloBoardId.value && trelloBoards.value.length > 0) { selectedTrelloBoardId.value = trelloBoards.value[0]?.id ?? null; } } catch (e: any) { @@ -595,6 +601,7 @@ export const useDashboardStore = defineStore('dashboard', () => { inProgress: rawBoard.inProgress || [], done: rawBoard.done || [], }; + trelloListIds.value = data.list_ids || {}; activities.value = data.all_activities || []; _lastFetchTime = Date.now(); } catch (e: any) { @@ -698,6 +705,7 @@ export const useDashboardStore = defineStore('dashboard', () => { activeSource.value = 'jira'; trelloBoards.value = []; selectedTrelloBoardId.value = null; + trelloListIds.value = {}; _lastFetchTime = 0; _lastFetchKey = null; _inflightDashboard = null; @@ -749,6 +757,7 @@ export const useDashboardStore = defineStore('dashboard', () => { activeSource, trelloBoards, selectedTrelloBoardId, + trelloListIds, fetchTrelloBoards, setActiveTrelloBoard, setActiveSource, diff --git a/src/utils/connectService.ts b/src/utils/connectService.ts index 3841643..8cbb00f 100644 --- a/src/utils/connectService.ts +++ b/src/utils/connectService.ts @@ -17,8 +17,7 @@ const ENDPOINTS: Record = { jira: '/api/auth/jira/connect', github: '/api/auth/github/connect', notion: '/api/auth/notion/connect', - // Trello shares the same Atlassian OAuth as Jira — reconnecting Jira grants Trello access - trello: '/api/auth/jira/connect', + trello: '/api/auth/trello/connect', }; /** diff --git a/src/views/AuthCallback.vue b/src/views/AuthCallback.vue index e6b9687..6053d5d 100644 --- a/src/views/AuthCallback.vue +++ b/src/views/AuthCallback.vue @@ -17,6 +17,7 @@ onMounted(async () => { const jiraConnected = route.query.jira_connected === "true"; const notionConnected = route.query.notion_connected === "true"; const githubConnected = route.query.github_connected === "true"; + const trelloConnected = route.query.trello_connected === "true"; const isNewUser = route.query.is_new_user === "true"; const openProfile = route.query.openProfile; @@ -49,6 +50,10 @@ onMounted(async () => { toast.success("Notion account connected successfully!"); } + if (trelloConnected) { + toast.success("Trello account connected successfully!"); + } + // Check onboarding status onboardingStore.checkOnboardingStatus(); @@ -57,7 +62,8 @@ onMounted(async () => { type: 'OAUTH_SUCCESS', jiraConnected, githubConnected, - notionConnected + notionConnected, + trelloConnected, }; // 1. Try BroadcastChannel (Modern & Robust) @@ -90,7 +96,7 @@ onMounted(async () => { // Return-from-integration callback → back to onboarding (to continue) // Completed users → dashboard if (!onboardingStore.onboardingCompleted) { - if (jiraConnected || githubConnected || notionConnected) { + if (jiraConnected || githubConnected || notionConnected || trelloConnected) { router.push({ path: "/onboarding", query: { step: 2 } }); } else { router.push("/onboarding"); diff --git a/src/views/settings/IntegrationsSettings.vue b/src/views/settings/IntegrationsSettings.vue index 428bd35..5fd19ad 100644 --- a/src/views/settings/IntegrationsSettings.vue +++ b/src/views/settings/IntegrationsSettings.vue @@ -56,10 +56,7 @@ const integrations = computed(() => [ description: 'Manage Trello boards and cards directly from your Kwillo dashboard.', logo: '/trello.svg', connected: authStore.trelloConnected, - color: 'hover:border-blue-500/20 hover:bg-blue-500/5', - note: authStore.jiraConnected && !authStore.trelloConnected - ? 'Reconnect Jira to enable Trello access' - : undefined + color: 'hover:border-blue-500/20 hover:bg-blue-500/5' } ]); @@ -140,12 +137,25 @@ const toggleIntegration = async (id: "jira" | "github" | "notion" | string) => { } } } else if (id === 'trello') { - // Trello uses the same Jira OAuth token — reconnect Jira to get Trello scopes - isConnecting.value[id] = true; - try { - await connectService('trello'); - } finally { - isConnecting.value[id] = false; + if (!authStore.trelloConnected) { + isConnecting.value[id] = true; + try { + await connectService('trello'); + } finally { + isConnecting.value[id] = false; + } + } else { + isConnecting.value[id] = true; + try { + await apiClient.delete("/api/auth/trello/disconnect"); + toast.success("Trello disconnected successfully"); + await authStore.fetchUser(); + } catch (error) { + console.error("Failed to disconnect Trello:", error); + toast.error("Failed to disconnect Trello. Please try again."); + } finally { + isConnecting.value[id] = false; + } } } else { console.log(`Toggling integration ${id}`);