diff --git a/app/api/twenty-crm/tasks/route.ts b/app/api/twenty-crm/tasks/route.ts index 9f0736f..e879821 100644 --- a/app/api/twenty-crm/tasks/route.ts +++ b/app/api/twenty-crm/tasks/route.ts @@ -6,16 +6,14 @@ import { logger } from "@/lib/logger"; interface TwentyTask { id: string; title: string; - body?: string; + bodyV2?: any; // Can be rich text/JSON dueAt?: string; - completedAt?: string; + status?: string; // e.g., "Done", "Todo", etc. type?: string; assigneeId?: string; assignee?: { id: string; - firstName?: string; - lastName?: string; - email?: string; + name?: string; }; } @@ -44,13 +42,16 @@ async function fetchTwentyTasks(): Promise { const todayISO = today.toISOString(); // GraphQL query to fetch tasks from Twenty CRM - // Twenty CRM uses different query structures - trying tasks query first - // If this doesn't work, we may need to use REST API or check the actual schema + // Based on error messages, using correct field names: + // - filter instead of where + // - bodyV2 instead of body + // - status field instead of completedAt (need to check what status values mean) + // - name instead of firstName/lastName/email for WorkspaceMember const query = ` query GetOverdueTasks { tasks( - where: { - completedAt: { is: NULL } + filter: { + status: { neq: Done } dueAt: { lt: "${todayISO}" } } orderBy: { dueAt: AscNullsLast } @@ -59,15 +60,13 @@ async function fetchTwentyTasks(): Promise { node { id title - body + bodyV2 dueAt - completedAt + status assigneeId assignee { id - firstName - lastName - email + name } } } @@ -151,20 +150,32 @@ async function fetchTwentyTasks(): Promise { // Transform Twenty CRM tasks to match our Task interface const tasks: TwentyTask[] = activitiesData.map((edge: any) => { const node = edge.node || edge; // Handle both edge.node and direct node + + // Extract text from bodyV2 if it's a rich text object + let bodyText = null; + if (node.bodyV2) { + if (typeof node.bodyV2 === 'string') { + bodyText = node.bodyV2; + } else if (node.bodyV2 && typeof node.bodyV2 === 'object') { + // Try to extract text from rich text structure + bodyText = JSON.stringify(node.bodyV2).substring(0, 200); + } + } + return { id: node.id, title: node.title || 'Untitled Task', - body: node.body || null, + bodyV2: node.bodyV2 || null, dueAt: node.dueAt || null, - completedAt: node.completedAt || null, + status: node.status || null, type: node.type || 'Task', assigneeId: node.assigneeId || null, assignee: node.assignee ? { id: node.assignee.id, - firstName: node.assignee.firstName || null, - lastName: node.assignee.lastName || null, - email: node.assignee.email || null, + name: node.assignee.name || null, } : null, + // Store extracted body text for easier access + _bodyText: bodyText, }; }); @@ -203,14 +214,14 @@ export async function GET(request: NextRequest) { const transformedTasks = tasks.map((task) => ({ id: `twenty-${task.id}`, // Prefix to avoid conflicts with Leantime IDs headline: task.title, - description: task.body || null, + description: (task as any)._bodyText || null, // Use extracted body text dateToFinish: task.dueAt || null, projectName: 'Twenty CRM', projectId: 0, - status: task.completedAt ? 5 : 1, // 5 = Done, 1 = New + status: task.status === 'Done' ? 5 : 1, // 5 = Done, 1 = New (or other status) editorId: task.assigneeId || null, - editorFirstname: task.assignee?.firstName || null, - editorLastname: task.assignee?.lastName || null, + editorFirstname: task.assignee?.name?.split(' ')[0] || null, // Extract first name from full name + editorLastname: task.assignee?.name?.split(' ').slice(1).join(' ') || null, // Extract last name from full name authorFirstname: null, authorLastname: null, milestoneHeadline: null, @@ -219,7 +230,7 @@ export async function GET(request: NextRequest) { type: 'twenty-crm', dependingTicketId: null, source: 'twenty-crm', // Add source identifier - url: process.env.TWENTY_CRM_URL ? `${process.env.TWENTY_CRM_URL}/object/activity/${task.id}` : null, + url: process.env.TWENTY_CRM_URL ? `${process.env.TWENTY_CRM_URL}/object/task/${task.id}` : null, })); logger.debug('[TWENTY_CRM_TASKS] Transformed tasks', {