Widget Devoir Finition
This commit is contained in:
parent
485c49523e
commit
b3ce739153
@ -246,7 +246,11 @@ export async function GET(request: NextRequest) {
|
|||||||
emailHash: Buffer.from(session.user.email.toLowerCase()).toString('base64').slice(0, 12),
|
emailHash: Buffer.from(session.user.email.toLowerCase()).toString('base64').slice(0, 12),
|
||||||
taskCount: filteredCachedTasks.length,
|
taskCount: filteredCachedTasks.length,
|
||||||
});
|
});
|
||||||
return NextResponse.json(filteredCachedTasks);
|
// Return tasks with done statuses for frontend filtering
|
||||||
|
return NextResponse.json({
|
||||||
|
tasks: filteredCachedTasks,
|
||||||
|
doneStatuses: Array.from(doneStatusValues),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -388,7 +392,11 @@ export async function GET(request: NextRequest) {
|
|||||||
// Cache the results
|
// Cache the results
|
||||||
await cacheTasksData(session.user.id, tasks);
|
await cacheTasksData(session.user.id, tasks);
|
||||||
|
|
||||||
return NextResponse.json(tasks);
|
// Return tasks with done statuses for frontend filtering
|
||||||
|
return NextResponse.json({
|
||||||
|
tasks: tasks,
|
||||||
|
doneStatuses: Array.from(doneStatusValues),
|
||||||
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
logger.error('[LEANTIME_TASKS] Error in tasks route', {
|
logger.error('[LEANTIME_TASKS] Error in tasks route', {
|
||||||
error: error instanceof Error ? error.message : String(error),
|
error: error instanceof Error ? error.message : String(error),
|
||||||
|
|||||||
@ -50,6 +50,7 @@ export function Duties() {
|
|||||||
const [refreshing, setRefreshing] = useState(false);
|
const [refreshing, setRefreshing] = useState(false);
|
||||||
const { triggerNotification } = useWidgetNotification();
|
const { triggerNotification } = useWidgetNotification();
|
||||||
const lastTaskCountRef = useRef<number>(-1);
|
const lastTaskCountRef = useRef<number>(-1);
|
||||||
|
const [leantimeDoneStatuses, setLeantimeDoneStatuses] = useState<Set<string>>(new Set(['0', '3', '5'])); // Fallback values
|
||||||
|
|
||||||
const getStatusLabel = (status: number): string => {
|
const getStatusLabel = (status: number): string => {
|
||||||
switch (status) {
|
switch (status) {
|
||||||
@ -114,9 +115,29 @@ export function Duties() {
|
|||||||
|
|
||||||
// Process Leantime tasks
|
// Process Leantime tasks
|
||||||
let leantimeTasks: Task[] = [];
|
let leantimeTasks: Task[] = [];
|
||||||
|
let currentDoneStatuses = new Set<string>(['0', '3', '5']); // Fallback values
|
||||||
if (leantimeResponse.status === 'fulfilled' && leantimeResponse.value.ok) {
|
if (leantimeResponse.status === 'fulfilled' && leantimeResponse.value.ok) {
|
||||||
const leantimeData = await leantimeResponse.value.json();
|
const leantimeResponseData = await leantimeResponse.value.json();
|
||||||
if (Array.isArray(leantimeData)) {
|
|
||||||
|
// Handle both formats: new format with {tasks, doneStatuses} or legacy array format
|
||||||
|
let leantimeData: Task[];
|
||||||
|
if (Array.isArray(leantimeResponseData)) {
|
||||||
|
// Legacy format: direct array
|
||||||
|
leantimeData = leantimeResponseData;
|
||||||
|
} else if (leantimeResponseData.tasks && Array.isArray(leantimeResponseData.tasks)) {
|
||||||
|
// New format: object with tasks and doneStatuses
|
||||||
|
leantimeData = leantimeResponseData.tasks;
|
||||||
|
if (leantimeResponseData.doneStatuses && Array.isArray(leantimeResponseData.doneStatuses)) {
|
||||||
|
currentDoneStatuses = new Set(leantimeResponseData.doneStatuses);
|
||||||
|
setLeantimeDoneStatuses(currentDoneStatuses);
|
||||||
|
console.log('[Devoirs Widget] ✅ Using dynamic done statuses from API:', leantimeResponseData.doneStatuses);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
console.warn('[Devoirs Widget] ⚠️ Invalid Leantime response format:', leantimeResponseData);
|
||||||
|
leantimeData = [];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (leantimeData.length > 0) {
|
||||||
// Log ALL tasks with their statuses to see what we receive
|
// Log ALL tasks with their statuses to see what we receive
|
||||||
console.log('[Devoirs Widget] 📥 RAW Leantime tasks from API:', leantimeData.map((t: any) => ({
|
console.log('[Devoirs Widget] 📥 RAW Leantime tasks from API:', leantimeData.map((t: any) => ({
|
||||||
id: t.id,
|
id: t.id,
|
||||||
@ -125,22 +146,6 @@ export function Duties() {
|
|||||||
statusType: typeof t.status,
|
statusType: typeof t.status,
|
||||||
})));
|
})));
|
||||||
leantimeTasks = leantimeData;
|
leantimeTasks = leantimeData;
|
||||||
// Log tasks with status 0, 3, or 5 (done) to debug
|
|
||||||
const doneTasks = leantimeData.filter((t: Task) => {
|
|
||||||
const taskStatus = (t as any).status; // Use any to handle potential string/number mismatch
|
|
||||||
if (taskStatus === null || taskStatus === undefined) return false;
|
|
||||||
const statusNum = typeof taskStatus === 'string' ? parseInt(taskStatus, 10) : taskStatus;
|
|
||||||
const statusStr = typeof taskStatus === 'string' ? taskStatus.toLowerCase() : String(taskStatus).toLowerCase();
|
|
||||||
return statusNum === 0 || statusNum === 3 || statusNum === 5 || statusStr === '0' || statusStr === '3' || statusStr === '5' || statusStr === 'done';
|
|
||||||
});
|
|
||||||
if (doneTasks.length > 0) {
|
|
||||||
console.warn('[Devoirs Widget] ⚠️ Received done tasks from Leantime API:', doneTasks.map((t: Task) => ({
|
|
||||||
id: t.id,
|
|
||||||
headline: t.headline,
|
|
||||||
status: t.status,
|
|
||||||
statusType: typeof t.status,
|
|
||||||
})));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.warn('Failed to fetch Leantime tasks:', leantimeResponse);
|
console.warn('Failed to fetch Leantime tasks:', leantimeResponse);
|
||||||
@ -165,7 +170,8 @@ export function Duties() {
|
|||||||
const rawStatus = (t as any).status;
|
const rawStatus = (t as any).status;
|
||||||
const statusNum = typeof rawStatus === 'string' ? parseInt(rawStatus, 10) : rawStatus;
|
const statusNum = typeof rawStatus === 'string' ? parseInt(rawStatus, 10) : rawStatus;
|
||||||
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 = statusNum === 0 || statusNum === 3 || statusNum === 5 || statusStr === '0' || statusStr === '3' || statusStr === '5' || statusStr === 'done';
|
// Use dynamic done statuses instead of hardcoded values
|
||||||
|
const isDone = currentDoneStatuses.has(String(rawStatus)) || currentDoneStatuses.has(statusStr);
|
||||||
return {
|
return {
|
||||||
id: t.id,
|
id: t.id,
|
||||||
headline: t.headline,
|
headline: t.headline,
|
||||||
@ -240,30 +246,43 @@ export function Duties() {
|
|||||||
const todayDay = now.getDate();
|
const todayDay = now.getDate();
|
||||||
|
|
||||||
const filteredTasks = allTasks.filter((task: Task) => {
|
const filteredTasks = allTasks.filter((task: Task) => {
|
||||||
// Exclude tasks with status Done
|
// FILTRE 1: Exclude tasks with status Done (using dynamic done statuses)
|
||||||
// In Leantime: status 3 = DONE (see api/leantime/status-labels/route.ts), also check status 5
|
|
||||||
const rawStatus = (task as any).status; // Use any to handle potential string/number mismatch
|
const rawStatus = (task as any).status; // Use any to handle potential string/number mismatch
|
||||||
if (rawStatus === null || rawStatus === undefined) {
|
if (rawStatus !== null && rawStatus !== undefined) {
|
||||||
// If status is null/undefined, keep the task (let other filters handle it)
|
const statusStr = String(rawStatus);
|
||||||
} else {
|
// Check if this task's status is in the done statuses set (for Leantime tasks)
|
||||||
const taskStatus = typeof rawStatus === 'string' ? parseInt(rawStatus, 10) : rawStatus;
|
// For Twenty CRM tasks, we still check the old way since they don't use dynamic statuses
|
||||||
const statusStr = typeof rawStatus === 'string' ? rawStatus.toLowerCase() : String(rawStatus).toLowerCase();
|
if (task.source === 'leantime' && currentDoneStatuses.has(statusStr)) {
|
||||||
if (taskStatus === 0 || taskStatus === 3 || taskStatus === 5 || statusStr === '0' || statusStr === '3' || statusStr === '5' || statusStr === 'done') {
|
|
||||||
console.log('[Devoirs Widget] Filtering out done task:', {
|
console.log('[Devoirs Widget] Filtering out done task:', {
|
||||||
id: task.id,
|
id: task.id,
|
||||||
headline: task.headline,
|
headline: task.headline,
|
||||||
status: rawStatus,
|
status: rawStatus,
|
||||||
taskStatus,
|
source: task.source,
|
||||||
});
|
});
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
// For Twenty CRM or legacy format, keep old check as fallback
|
||||||
|
if (task.source !== 'leantime') {
|
||||||
|
const taskStatus = typeof rawStatus === 'string' ? parseInt(rawStatus, 10) : rawStatus;
|
||||||
|
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') {
|
||||||
|
console.log('[Devoirs Widget] Filtering out done task (Twenty CRM):', {
|
||||||
|
id: task.id,
|
||||||
|
headline: task.headline,
|
||||||
|
status: rawStatus,
|
||||||
|
});
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FILTRE 2: Exclude tasks without a due date
|
||||||
const dueDate = getValidDate(task);
|
const dueDate = getValidDate(task);
|
||||||
if (!dueDate) {
|
if (!dueDate) {
|
||||||
return false; // Exclude tasks without a due date
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FILTRE 3: Keep tasks with due date <= today (overdue or due today, not future)
|
||||||
// Use local date comparison to avoid timezone issues
|
// Use local date comparison to avoid timezone issues
|
||||||
// Leantime dates with 'Z' are actually local time, not UTC - remove Z before parsing
|
// Leantime dates with 'Z' are actually local time, not UTC - remove Z before parsing
|
||||||
const dateStrForParsing = dueDate.endsWith('Z') ? dueDate.slice(0, -1) : dueDate;
|
const dateStrForParsing = dueDate.endsWith('Z') ? dueDate.slice(0, -1) : dueDate;
|
||||||
@ -375,6 +394,21 @@ export function Duties() {
|
|||||||
if (rawStatus === null || rawStatus === undefined) {
|
if (rawStatus === null || rawStatus === undefined) {
|
||||||
return true; // Keep tasks without status
|
return true; // Keep tasks without status
|
||||||
}
|
}
|
||||||
|
// Use dynamic done statuses for Leantime tasks
|
||||||
|
if (task.source === 'leantime') {
|
||||||
|
const statusStr = String(rawStatus);
|
||||||
|
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 true;
|
||||||
|
}
|
||||||
|
// For Twenty CRM tasks, use old check as fallback
|
||||||
const taskStatus = typeof rawStatus === 'string' ? parseInt(rawStatus, 10) : rawStatus;
|
const taskStatus = typeof rawStatus === 'string' ? parseInt(rawStatus, 10) : rawStatus;
|
||||||
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';
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user