widget leantime refactor

This commit is contained in:
alma 2026-01-15 23:14:35 +01:00
parent b4099d507e
commit 90bde85c5c

View File

@ -23,10 +23,90 @@ interface TwentyTask {
};
}
/**
* Get Twenty CRM workspace member ID by email
*/
async function getTwentyCrmUserId(email: string): Promise<string | null> {
try {
if (!process.env.TWENTY_CRM_API_URL || !process.env.TWENTY_CRM_API_KEY) {
return null;
}
const apiUrl = process.env.TWENTY_CRM_API_URL.endsWith('/graphql')
? process.env.TWENTY_CRM_API_URL
: `${process.env.TWENTY_CRM_API_URL}/graphql`;
// Query to find workspace member by email
const query = `
query GetWorkspaceMemberByEmail {
workspaceMembers {
edges {
node {
id
user {
email
}
}
}
}
}
`;
const response = await fetch(apiUrl, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.TWENTY_CRM_API_KEY}`,
},
body: JSON.stringify({ query }),
});
if (!response.ok) {
logger.error('[TWENTY_CRM_TASKS] Failed to fetch workspace members', {
status: response.status,
});
return null;
}
const data = await response.json();
if (data.errors) {
logger.error('[TWENTY_CRM_TASKS] GraphQL errors fetching workspace members', {
errors: data.errors,
});
return null;
}
// Find workspace member with matching email
const members = data.data?.workspaceMembers?.edges || [];
const member = members.find((edge: any) =>
edge.node?.user?.email?.toLowerCase() === email.toLowerCase()
);
if (member) {
logger.debug('[TWENTY_CRM_TASKS] Found workspace member', {
memberId: member.node.id,
emailHash: Buffer.from(email.toLowerCase()).toString('base64').slice(0, 12),
});
return member.node.id;
}
logger.warn('[TWENTY_CRM_TASKS] Workspace member not found', {
emailHash: Buffer.from(email.toLowerCase()).toString('base64').slice(0, 12),
});
return null;
} catch (error) {
logger.error('[TWENTY_CRM_TASKS] Error fetching workspace member', {
error: error instanceof Error ? error.message : String(error),
});
return null;
}
}
/**
* Fetch tasks from Twenty CRM using GraphQL API
*/
async function fetchTwentyTasks(): Promise<TwentyTask[]> {
async function fetchTwentyTasks(userId?: string): Promise<TwentyTask[]> {
try {
if (!process.env.TWENTY_CRM_API_URL) {
logger.error('[TWENTY_CRM_TASKS] TWENTY_CRM_API_URL is not set in environment variables');
@ -216,18 +296,40 @@ async function fetchTwentyTasks(): Promise<TwentyTask[]> {
title: t.title,
status: t.status,
dueAt: t.dueAt,
assigneeId: t.assigneeId,
hasDueDate: !!t.dueAt,
})),
});
// Filter client-side for overdue tasks (dueAt < today) and not completed (status !== 'Done')
// Filter by assignee if userId is provided
let filteredByAssignee = allTasks;
if (userId) {
filteredByAssignee = allTasks.filter((task: TwentyTask) => {
const isAssignedToUser = task.assigneeId === userId;
if (!isAssignedToUser) {
logger.debug('[TWENTY_CRM_TASKS] Filtering out task not assigned to user', {
id: task.id,
assigneeId: task.assigneeId,
userId,
});
}
return isAssignedToUser;
});
logger.error('[TWENTY_CRM_TASKS] Tasks after assignee filter', {
before: allTasks.length,
after: filteredByAssignee.length,
userId,
});
}
// Filter client-side for overdue tasks (dueAt <= today) and not completed (status !== 'Done')
// Use local date for comparison to avoid timezone issues
const now = new Date();
const todayYear = now.getFullYear();
const todayMonth = now.getMonth();
const todayDay = now.getDate();
const tasks: TwentyTask[] = allTasks
const tasks: TwentyTask[] = filteredByAssignee
.filter((task: TwentyTask) => {
// Filter: only overdue tasks (dueAt < today) and not completed
if (task.status === 'Done') {
@ -311,7 +413,22 @@ export async function GET(request: NextRequest) {
forceRefresh,
});
const tasks = await fetchTwentyTasks();
// Get Twenty CRM user ID from email
const twentyCrmUserId = await getTwentyCrmUserId(session.user.email);
if (!twentyCrmUserId) {
logger.warn('[TWENTY_CRM_TASKS] User not found in Twenty CRM, returning empty tasks', {
emailHash: Buffer.from(session.user.email.toLowerCase()).toString('base64').slice(0, 12),
});
return NextResponse.json([]);
}
logger.debug('[TWENTY_CRM_TASKS] Found Twenty CRM user ID', {
userId: twentyCrmUserId,
emailHash: Buffer.from(session.user.email.toLowerCase()).toString('base64').slice(0, 12),
});
const tasks = await fetchTwentyTasks(twentyCrmUserId);
// Transform to match Leantime task format for consistency
const transformedTasks = tasks.map((task) => ({