Widget Devoir Finition
This commit is contained in:
parent
6af464eb70
commit
099c3b61bd
@ -113,8 +113,6 @@ async function getDoneStatusValues(userId: number): Promise<Set<string>> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!data.result || typeof data.result !== 'object' || Array.isArray(data.result)) {
|
if (!data.result || typeof data.result !== 'object' || Array.isArray(data.result)) {
|
||||||
console.log('[LEANTIME_TASKS] ⚠️ Invalid response format from getAllStatusLabelsByUserId, using fallback');
|
|
||||||
console.log('[LEANTIME_TASKS] Response type:', typeof data.result, 'isArray:', Array.isArray(data.result));
|
|
||||||
logger.warn('[LEANTIME_TASKS] Invalid response format from getAllStatusLabelsByUserId, using fallback');
|
logger.warn('[LEANTIME_TASKS] Invalid response format from getAllStatusLabelsByUserId, using fallback');
|
||||||
// Fallback to default values if API fails
|
// Fallback to default values if API fails
|
||||||
return new Set(['0', '3', '5']);
|
return new Set(['0', '3', '5']);
|
||||||
@ -124,12 +122,6 @@ async function getDoneStatusValues(userId: number): Promise<Set<string>> {
|
|||||||
// - Keys are project IDs (strings like "4", "5", "6", "457")
|
// - Keys are project IDs (strings like "4", "5", "6", "457")
|
||||||
// - Values are objects where keys are status numbers (strings like "0", "1", "2", "3", "4", "5", "-1")
|
// - Values are objects where keys are status numbers (strings like "0", "1", "2", "3", "4", "5", "-1")
|
||||||
// - Each status object has: name, statusType, class, kanbanCol, sortKey
|
// - Each status object has: name, statusType, class, kanbanCol, sortKey
|
||||||
|
|
||||||
console.log('[LEANTIME_TASKS] 📋 getAllStatusLabelsByUserId response structure:', {
|
|
||||||
resultType: typeof data.result,
|
|
||||||
isObject: typeof data.result === 'object',
|
|
||||||
projectIds: Object.keys(data.result),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Iterate through all projects
|
// Iterate through all projects
|
||||||
Object.keys(data.result).forEach((projectId: string) => {
|
Object.keys(data.result).forEach((projectId: string) => {
|
||||||
@ -148,17 +140,12 @@ async function getDoneStatusValues(userId: number): Promise<Set<string>> {
|
|||||||
if (statusType === 'DONE' || statusName === 'done' || statusName.includes('done')) {
|
if (statusType === 'DONE' || statusName === 'done' || statusName.includes('done')) {
|
||||||
// The statusKey IS the status number (e.g., "0", "3", "5", "-1")
|
// The statusKey IS the status number (e.g., "0", "3", "5", "-1")
|
||||||
doneStatusValues.add(statusKey);
|
doneStatusValues.add(statusKey);
|
||||||
console.log(`[LEANTIME_TASKS] ✅ Found done status: ${statusKey} in project ${projectId} (name: "${statusInfo.name}", statusType: "${statusType}")`);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('[LEANTIME_TASKS] ✅ Identified done status values:', {
|
|
||||||
doneStatusValues: Array.from(doneStatusValues),
|
|
||||||
projectsCount: Object.keys(data.result).length,
|
|
||||||
});
|
|
||||||
logger.debug('[LEANTIME_TASKS] Identified done status values', {
|
logger.debug('[LEANTIME_TASKS] Identified done status values', {
|
||||||
doneStatusValues: Array.from(doneStatusValues),
|
doneStatusValues: Array.from(doneStatusValues),
|
||||||
projectsCount: Object.keys(data.result).length,
|
projectsCount: Object.keys(data.result).length,
|
||||||
@ -181,14 +168,11 @@ async function getDoneStatusValues(userId: number): Promise<Set<string>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export async function GET(request: NextRequest) {
|
export async function GET(request: NextRequest) {
|
||||||
console.log('[LEANTIME_TASKS] 🔵 API CALLED - Starting request');
|
|
||||||
try {
|
try {
|
||||||
const session = await getServerSession(authOptions);
|
const session = await getServerSession(authOptions);
|
||||||
if (!session?.user?.email) {
|
if (!session?.user?.email) {
|
||||||
console.log('[LEANTIME_TASKS] ❌ Unauthorized - no session');
|
|
||||||
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||||
}
|
}
|
||||||
console.log('[LEANTIME_TASKS] ✅ Session found, user:', session.user.email);
|
|
||||||
|
|
||||||
// Check for force refresh parameter
|
// Check for force refresh parameter
|
||||||
const url = new URL(request.url);
|
const url = new URL(request.url);
|
||||||
@ -206,7 +190,6 @@ export async function GET(request: NextRequest) {
|
|||||||
|
|
||||||
// Get done status values dynamically from Leantime status labels
|
// Get done status values dynamically from Leantime status labels
|
||||||
const doneStatusValues = await getDoneStatusValues(userId);
|
const doneStatusValues = await getDoneStatusValues(userId);
|
||||||
console.log('[LEANTIME_TASKS] ✅ Done status values for filtering:', Array.from(doneStatusValues));
|
|
||||||
logger.debug('[LEANTIME_TASKS] Done status values identified', {
|
logger.debug('[LEANTIME_TASKS] Done status values identified', {
|
||||||
doneStatusValues: Array.from(doneStatusValues),
|
doneStatusValues: Array.from(doneStatusValues),
|
||||||
});
|
});
|
||||||
@ -291,12 +274,6 @@ export async function GET(request: NextRequest) {
|
|||||||
throw new Error('Invalid response format from Leantime');
|
throw new Error('Invalid response format from Leantime');
|
||||||
}
|
}
|
||||||
|
|
||||||
console.log('[LEANTIME_TASKS] 🔍 RAW DATA FROM LEANTIME - Total tasks:', data.result.length);
|
|
||||||
// Log RAW data from Leantime to see exact status values (using console.log so it shows in production)
|
|
||||||
data.result.forEach((task: any) => {
|
|
||||||
console.log(`[LEANTIME_TASKS] Task ID: ${task.id}, Headline: ${task.headline}, Status: ${task.status} (type: ${typeof task.status}), EditorId: ${task.editorId}`);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Log detailed status information before filtering
|
// Log detailed status information before filtering
|
||||||
const statusBreakdownBefore = data.result.reduce((acc: any, task: any) => {
|
const statusBreakdownBefore = data.result.reduce((acc: any, task: any) => {
|
||||||
const status = task.status;
|
const status = task.status;
|
||||||
@ -342,9 +319,6 @@ export async function GET(request: NextRequest) {
|
|||||||
// Only show tasks where the user is the editor
|
// Only show tasks where the user is the editor
|
||||||
const isUserEditor = taskEditorId === currentUserId;
|
const isUserEditor = taskEditorId === currentUserId;
|
||||||
|
|
||||||
if (!isUserEditor) {
|
|
||||||
console.log(`[LEANTIME_TASKS] ⚠️ Task filtered - user is not editor: ID=${task.id}, EditorId=${taskEditorId}, UserId=${currentUserId}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return isUserEditor;
|
return isUserEditor;
|
||||||
})
|
})
|
||||||
|
|||||||
@ -131,26 +131,15 @@ export function Duties() {
|
|||||||
if (leantimeResponseData.doneStatuses && Array.isArray(leantimeResponseData.doneStatuses)) {
|
if (leantimeResponseData.doneStatuses && Array.isArray(leantimeResponseData.doneStatuses)) {
|
||||||
currentDoneStatuses = new Set(leantimeResponseData.doneStatuses);
|
currentDoneStatuses = new Set(leantimeResponseData.doneStatuses);
|
||||||
setLeantimeDoneStatuses(currentDoneStatuses);
|
setLeantimeDoneStatuses(currentDoneStatuses);
|
||||||
console.log('[Devoirs Widget] ✅ Using dynamic done statuses from API:', leantimeResponseData.doneStatuses);
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('[Devoirs Widget] ⚠️ Invalid Leantime response format:', leantimeResponseData);
|
|
||||||
leantimeData = [];
|
leantimeData = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (leantimeData.length > 0) {
|
if (leantimeData.length > 0) {
|
||||||
// Log ALL tasks with their statuses to see what we receive
|
|
||||||
console.log('[Devoirs Widget] 📥 RAW Leantime tasks from API:', leantimeData.map((t: any) => ({
|
|
||||||
id: t.id,
|
|
||||||
headline: t.headline,
|
|
||||||
status: t.status,
|
|
||||||
statusType: typeof t.status,
|
|
||||||
})));
|
|
||||||
// Mark tasks with source
|
// Mark tasks with source
|
||||||
leantimeTasks = leantimeData.map((t: Task) => ({ ...t, source: 'leantime' as const }));
|
leantimeTasks = leantimeData.map((t: Task) => ({ ...t, source: 'leantime' as const }));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
console.warn('Failed to fetch Leantime tasks:', leantimeResponse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process Twenty CRM tasks
|
// Process Twenty CRM tasks
|
||||||
@ -161,79 +150,11 @@ export function Duties() {
|
|||||||
// Mark tasks with source
|
// Mark tasks with source
|
||||||
twentyCrmTasks = twentyCrmData.map((t: Task) => ({ ...t, source: 'twenty-crm' as const }));
|
twentyCrmTasks = twentyCrmData.map((t: Task) => ({ ...t, source: 'twenty-crm' as const }));
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
console.warn('Failed to fetch Twenty CRM tasks:', twentyCrmResponse);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine tasks from both sources
|
// Combine tasks from both sources
|
||||||
const allTasks = [...leantimeTasks, ...twentyCrmTasks];
|
const allTasks = [...leantimeTasks, ...twentyCrmTasks];
|
||||||
|
|
||||||
// Log detailed status information
|
|
||||||
const leantimeStatusDetails = leantimeTasks.map((t: Task) => {
|
|
||||||
const rawStatus = (t as any).status;
|
|
||||||
const statusNum = typeof rawStatus === 'string' ? parseInt(rawStatus, 10) : rawStatus;
|
|
||||||
const statusStr = typeof rawStatus === 'string' ? rawStatus.toLowerCase().trim() : String(rawStatus).toLowerCase().trim();
|
|
||||||
// Use dynamic done statuses instead of hardcoded values
|
|
||||||
const isDone = currentDoneStatuses.has(String(rawStatus)) || currentDoneStatuses.has(statusStr);
|
|
||||||
return {
|
|
||||||
id: t.id,
|
|
||||||
headline: t.headline,
|
|
||||||
status: rawStatus,
|
|
||||||
statusType: typeof rawStatus,
|
|
||||||
statusNum,
|
|
||||||
statusStr,
|
|
||||||
isDone,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
// Group by status for better visibility
|
|
||||||
const statusGroups = leantimeStatusDetails.reduce((acc: any, t) => {
|
|
||||||
const key = String(t.status);
|
|
||||||
if (!acc[key]) {
|
|
||||||
acc[key] = { status: t.status, count: 0, tasks: [] };
|
|
||||||
}
|
|
||||||
acc[key].count++;
|
|
||||||
if (acc[key].tasks.length < 3) {
|
|
||||||
acc[key].tasks.push({ id: t.id, headline: t.headline });
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, {});
|
|
||||||
|
|
||||||
const doneTasks = leantimeStatusDetails.filter(t => t.isDone);
|
|
||||||
|
|
||||||
// Always log status breakdown for debugging
|
|
||||||
const statusGroupsArray = Object.keys(statusGroups).map(key => ({
|
|
||||||
status: key,
|
|
||||||
count: statusGroups[key].count,
|
|
||||||
sample: statusGroups[key].tasks,
|
|
||||||
}));
|
|
||||||
console.log('[Devoirs Widget] 📊 Status Breakdown:', {
|
|
||||||
totalTasks: leantimeTasks.length,
|
|
||||||
statusGroups: statusGroupsArray,
|
|
||||||
doneTasksCount: doneTasks.length,
|
|
||||||
allStatuses: leantimeStatusDetails.map(t => `${t.id}:${t.status}(${t.statusType})`),
|
|
||||||
});
|
|
||||||
|
|
||||||
if (doneTasks.length > 0) {
|
|
||||||
console.error('[Devoirs Widget] ❌❌❌ FOUND DONE TASKS - THEY SHOULD BE FILTERED ❌❌❌', {
|
|
||||||
total: leantimeTasks.length,
|
|
||||||
doneCount: doneTasks.length,
|
|
||||||
doneTasks: doneTasks.map(t => ({
|
|
||||||
id: t.id,
|
|
||||||
headline: t.headline,
|
|
||||||
status: t.status,
|
|
||||||
statusType: t.statusType,
|
|
||||||
statusNum: t.statusNum,
|
|
||||||
statusStr: t.statusStr,
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log('[Devoirs Widget] Combined tasks:', {
|
|
||||||
leantime: leantimeTasks.length,
|
|
||||||
twentyCrm: twentyCrmTasks.length,
|
|
||||||
total: allTasks.length,
|
|
||||||
});
|
|
||||||
|
|
||||||
if (allTasks.length === 0) {
|
if (allTasks.length === 0) {
|
||||||
setTasks([]);
|
setTasks([]);
|
||||||
@ -256,12 +177,6 @@ export function Duties() {
|
|||||||
// Check if this task's status is in the done statuses set (for Leantime tasks)
|
// Check if this task's status is in the done statuses set (for Leantime tasks)
|
||||||
// For Twenty CRM tasks, we still check the old way since they don't use dynamic statuses
|
// For Twenty CRM tasks, we still check the old way since they don't use dynamic statuses
|
||||||
if (task.source === 'leantime' && currentDoneStatuses.has(statusStr)) {
|
if (task.source === 'leantime' && currentDoneStatuses.has(statusStr)) {
|
||||||
console.log('[Devoirs Widget] Filtering out done task:', {
|
|
||||||
id: task.id,
|
|
||||||
headline: task.headline,
|
|
||||||
status: rawStatus,
|
|
||||||
source: task.source,
|
|
||||||
});
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
// For Twenty CRM or legacy format, keep old check as fallback
|
// For Twenty CRM or legacy format, keep old check as fallback
|
||||||
@ -269,11 +184,6 @@ export function Duties() {
|
|||||||
const taskStatus = typeof rawStatus === 'string' ? parseInt(rawStatus, 10) : rawStatus;
|
const taskStatus = typeof rawStatus === 'string' ? parseInt(rawStatus, 10) : rawStatus;
|
||||||
const statusStrLower = typeof rawStatus === 'string' ? rawStatus.toLowerCase() : String(rawStatus).toLowerCase();
|
const statusStrLower = typeof rawStatus === 'string' ? rawStatus.toLowerCase() : String(rawStatus).toLowerCase();
|
||||||
if (taskStatus === 0 || taskStatus === 3 || taskStatus === 5 || statusStrLower === '0' || statusStrLower === '3' || statusStrLower === '5' || statusStrLower === 'done') {
|
if (taskStatus === 0 || taskStatus === 3 || taskStatus === 5 || statusStrLower === '0' || statusStrLower === '3' || statusStrLower === '5' || statusStrLower === 'done') {
|
||||||
console.log('[Devoirs Widget] Filtering out done task (Twenty CRM):', {
|
|
||||||
id: task.id,
|
|
||||||
headline: task.headline,
|
|
||||||
status: rawStatus,
|
|
||||||
});
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -302,17 +212,6 @@ export function Duties() {
|
|||||||
return isOverdueOrDueToday;
|
return isOverdueOrDueToday;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Log filtered results
|
|
||||||
console.log('[Devoirs Widget] Filtering results:', {
|
|
||||||
before: allTasks.length,
|
|
||||||
after: filteredTasks.length,
|
|
||||||
filteredOut: allTasks.length - filteredTasks.length,
|
|
||||||
filteredTasksStatuses: filteredTasks.map((t: Task) => ({
|
|
||||||
id: t.id,
|
|
||||||
headline: t.headline,
|
|
||||||
status: (t as any).status,
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
|
|
||||||
// Sort by dateToFinish (oldest first)
|
// Sort by dateToFinish (oldest first)
|
||||||
const sortedTasks = filteredTasks
|
const sortedTasks = filteredTasks
|
||||||
@ -338,14 +237,6 @@ export function Duties() {
|
|||||||
return 0;
|
return 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
console.log('Sorted tasks:', sortedTasks.map(t => ({
|
|
||||||
id: t.id,
|
|
||||||
date: t.dateToFinish,
|
|
||||||
status: t.status,
|
|
||||||
type: t.type || 'main',
|
|
||||||
source: (t as any).source || 'leantime'
|
|
||||||
})));
|
|
||||||
|
|
||||||
// Calculate current task count
|
// Calculate current task count
|
||||||
const currentTaskCount = sortedTasks.length;
|
const currentTaskCount = sortedTasks.length;
|
||||||
|
|
||||||
@ -401,12 +292,6 @@ export function Duties() {
|
|||||||
if (task.source === 'leantime') {
|
if (task.source === 'leantime') {
|
||||||
const statusStr = String(rawStatus);
|
const statusStr = String(rawStatus);
|
||||||
if (currentDoneStatuses.has(statusStr)) {
|
if (currentDoneStatuses.has(statusStr)) {
|
||||||
console.warn('[Devoirs Widget] ⚠️ Filtering out done task before notification:', {
|
|
||||||
id: task.id,
|
|
||||||
headline: task.headline,
|
|
||||||
status: rawStatus,
|
|
||||||
source: task.source,
|
|
||||||
});
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -416,11 +301,6 @@ export function Duties() {
|
|||||||
const statusStr = typeof rawStatus === 'string' ? rawStatus.toLowerCase().trim() : String(rawStatus).toLowerCase().trim();
|
const statusStr = typeof rawStatus === 'string' ? rawStatus.toLowerCase().trim() : String(rawStatus).toLowerCase().trim();
|
||||||
const isDone = taskStatus === 0 || taskStatus === 3 || taskStatus === 5 || statusStr === '0' || statusStr === '3' || statusStr === '5' || statusStr === 'done';
|
const isDone = taskStatus === 0 || taskStatus === 3 || taskStatus === 5 || statusStr === '0' || statusStr === '3' || statusStr === '5' || statusStr === 'done';
|
||||||
if (isDone) {
|
if (isDone) {
|
||||||
console.warn('[Devoirs Widget] ⚠️ Filtering out done task before notification:', {
|
|
||||||
id: task.id,
|
|
||||||
headline: task.headline,
|
|
||||||
status: rawStatus,
|
|
||||||
});
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -434,25 +314,14 @@ export function Duties() {
|
|||||||
url: (task as any).url || null,
|
url: (task as any).url || null,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
console.log('[Devoirs Widget] 📋 Dispatching tasks update', {
|
|
||||||
tasksCount: tasksForNotification.length,
|
|
||||||
tasks: tasksForNotification.map(t => ({
|
|
||||||
id: t.id,
|
|
||||||
title: t.headline,
|
|
||||||
dateToFinish: t.dateToFinish,
|
|
||||||
source: t.source,
|
|
||||||
})),
|
|
||||||
});
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
window.dispatchEvent(new CustomEvent('tasks-updated', {
|
window.dispatchEvent(new CustomEvent('tasks-updated', {
|
||||||
detail: {
|
detail: {
|
||||||
tasks: tasksForNotification,
|
tasks: tasksForNotification,
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
console.log('[Devoirs Widget] ✅ Event dispatched successfully');
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('[Devoirs Widget] ❌ Error dispatching event', error);
|
console.error('[Devoirs Widget] Error dispatching event', error);
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Error fetching tasks:', error);
|
console.error('Error fetching tasks:', error);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user