working leantime widget 19
This commit is contained in:
parent
bdca2c6252
commit
9b7f0bc78a
@ -8,8 +8,14 @@ interface Task {
|
||||
projectName: string;
|
||||
status: string;
|
||||
dueDate: string | null;
|
||||
details?: string;
|
||||
milestone?: string;
|
||||
details?: string | null;
|
||||
milestone?: string | null;
|
||||
class: string;
|
||||
}
|
||||
|
||||
interface Project {
|
||||
id: number;
|
||||
name: string;
|
||||
}
|
||||
|
||||
// Cache for user IDs
|
||||
@ -132,68 +138,53 @@ export async function GET() {
|
||||
console.log('Projects response:', JSON.stringify(projectsData, null, 2));
|
||||
|
||||
const projectsMap = new Map(
|
||||
projectsData.result.map((project: any) => [project.id, project.name])
|
||||
projectsData.result.map((project: Project) => [project.id, project.name])
|
||||
);
|
||||
|
||||
// Define status code mapping
|
||||
const statusMapping: Record<string, string> = {
|
||||
'-1': 'archived',
|
||||
'0': 'new',
|
||||
'1': 'in progress',
|
||||
'2': 'waiting',
|
||||
'3': 'in review',
|
||||
'4': 'done'
|
||||
};
|
||||
|
||||
// Transform the nested structure into a flat array of tasks
|
||||
const tasks: Task[] = [];
|
||||
Object.entries(data.result).forEach(([projectId, statusGroups]) => {
|
||||
const projectName = projectsMap.get(Number(projectId)) || `Project ${projectId}`;
|
||||
const project = projectsData.result.find((p: Project) => p.id === Number(projectId));
|
||||
const projectName = project ? project.name : `Project ${projectId}`;
|
||||
|
||||
if (typeof statusGroups === 'object' && statusGroups !== null) {
|
||||
// Iterate through each status group
|
||||
Object.entries(statusGroups).forEach(([statusType, statusLabels]) => {
|
||||
if (typeof statusLabels === 'object' && statusLabels !== null) {
|
||||
// Each status label in the group
|
||||
Object.values(statusLabels).forEach((label: any) => {
|
||||
const statusName = statusMapping[statusType] || `status-${statusType}`;
|
||||
const headline = String(label.title || label.name || statusName);
|
||||
|
||||
tasks.push({
|
||||
id: label.id?.toString() || `${projectId}-${statusType}`,
|
||||
headline,
|
||||
projectName,
|
||||
status: statusName,
|
||||
dueDate: null,
|
||||
details: label.description || null,
|
||||
milestone: label.milestone || null
|
||||
});
|
||||
Object.entries(statusGroups).forEach(([_, label]) => {
|
||||
if (typeof label === 'object' && label !== null && 'name' in label) {
|
||||
const statusLabel = label as {
|
||||
name: string;
|
||||
class: string;
|
||||
statusType: string;
|
||||
kanbanCol: string;
|
||||
sortKey: string;
|
||||
};
|
||||
|
||||
tasks.push({
|
||||
id: `${projectId}-${statusLabel.sortKey}`,
|
||||
headline: statusLabel.name,
|
||||
projectName,
|
||||
status: statusLabel.statusType.toLowerCase(),
|
||||
dueDate: null,
|
||||
details: undefined,
|
||||
milestone: undefined,
|
||||
class: statusLabel.class
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Sort tasks by status type
|
||||
const statusOrder: Record<string, number> = {
|
||||
'new': 1,
|
||||
'in progress': 2,
|
||||
'waiting': 3,
|
||||
'in review': 4,
|
||||
'done': 5,
|
||||
'archived': 6
|
||||
};
|
||||
|
||||
// Sort tasks by their sortKey
|
||||
tasks.sort((a, b) => {
|
||||
const statusA = statusOrder[a.status.toLowerCase()] || 99;
|
||||
const statusB = statusOrder[b.status.toLowerCase()] || 99;
|
||||
return statusA - statusB;
|
||||
const sortKeyA = Number(a.id.split('-')[1]) || 99;
|
||||
const sortKeyB = Number(b.id.split('-')[1]) || 99;
|
||||
return sortKeyA - sortKeyB;
|
||||
});
|
||||
|
||||
// Deduplicate tasks based on project and status
|
||||
// Deduplicate tasks based on headline and status
|
||||
const uniqueTasks = tasks.reduce((acc: Task[], task) => {
|
||||
const existingTask = acc.find(t =>
|
||||
t.projectName === task.projectName &&
|
||||
t.headline === task.headline &&
|
||||
t.status === task.status
|
||||
);
|
||||
|
||||
|
||||
@ -4,7 +4,6 @@ import { useEffect, useState } from "react";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { RefreshCw } from "lucide-react";
|
||||
import { formatDate } from "@/lib/utils";
|
||||
|
||||
interface Task {
|
||||
id: string;
|
||||
@ -12,8 +11,9 @@ interface Task {
|
||||
projectName: string;
|
||||
status: string;
|
||||
dueDate: string | null;
|
||||
details?: string;
|
||||
milestone?: string;
|
||||
details?: string | null;
|
||||
milestone?: string | null;
|
||||
class: string;
|
||||
}
|
||||
|
||||
export function Flow() {
|
||||
@ -63,25 +63,6 @@ export function Flow() {
|
||||
};
|
||||
}, []);
|
||||
|
||||
const getStatusColor = (status: string) => {
|
||||
switch (status.toLowerCase()) {
|
||||
case 'new':
|
||||
return 'text-blue-600';
|
||||
case 'blocked':
|
||||
return 'text-red-600';
|
||||
case 'in progress':
|
||||
case 'inprogress':
|
||||
return 'text-orange-600';
|
||||
case 'done':
|
||||
case 'archived':
|
||||
return 'text-green-600';
|
||||
case 'waiting for approval':
|
||||
return 'text-yellow-600';
|
||||
default:
|
||||
return 'text-gray-600';
|
||||
}
|
||||
};
|
||||
|
||||
// Group tasks by project
|
||||
const groupedTasks = tasks.reduce((acc, task) => {
|
||||
if (!acc[task.projectName]) {
|
||||
@ -124,18 +105,8 @@ export function Flow() {
|
||||
<div key={task.id} className="flex justify-between items-start text-sm border-b border-gray-100 pb-2">
|
||||
<div className="flex-1">
|
||||
<div className="font-medium">{task.headline}</div>
|
||||
{task.milestone && (
|
||||
<div className="text-xs text-gray-500 mt-1">
|
||||
{task.milestone}
|
||||
</div>
|
||||
)}
|
||||
{task.dueDate && (
|
||||
<div className="text-xs text-gray-500 mt-1">
|
||||
{formatDate(task.dueDate)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className={`ml-4 ${getStatusColor(task.status)}`}>
|
||||
<div className={`ml-4 px-2 py-1 rounded text-xs ${getLabelClass(task.class)}`}>
|
||||
{task.status.toUpperCase()}
|
||||
</div>
|
||||
</div>
|
||||
@ -148,4 +119,18 @@ export function Flow() {
|
||||
</CardContent>
|
||||
</Card>
|
||||
);
|
||||
}
|
||||
|
||||
function getLabelClass(className: string): string {
|
||||
const classMap: Record<string, string> = {
|
||||
'label-default': 'bg-gray-100 text-gray-800',
|
||||
'label-success': 'bg-green-100 text-green-800',
|
||||
'label-warning': 'bg-yellow-100 text-yellow-800',
|
||||
'label-info': 'bg-blue-100 text-blue-800',
|
||||
'label-blue': 'bg-blue-100 text-blue-800',
|
||||
'label-darker-blue': 'bg-indigo-100 text-indigo-800',
|
||||
'label-dark-green': 'bg-emerald-100 text-emerald-800',
|
||||
};
|
||||
|
||||
return classMap[className] || 'bg-gray-100 text-gray-800';
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user