working leantime widget 57
This commit is contained in:
parent
d4b50b8890
commit
f361f11c98
@ -11,6 +11,9 @@ interface Task {
|
||||
dueDate: string | null;
|
||||
milestone: string | null;
|
||||
details: string | null;
|
||||
createdOn: string;
|
||||
editedOn: string | null;
|
||||
assignedTo: number[];
|
||||
}
|
||||
|
||||
async function getLeantimeUserId(email: string): Promise<number | null> {
|
||||
@ -147,24 +150,30 @@ export async function GET(request: NextRequest) {
|
||||
throw new Error('Invalid response format from Leantime');
|
||||
}
|
||||
|
||||
const tasks = data.result.map((task: any) => ({
|
||||
id: task.id.toString(),
|
||||
headline: task.headline,
|
||||
projectName: task.projectName,
|
||||
projectId: task.projectId,
|
||||
status: task.status,
|
||||
dueDate: task.dateToFinish || null,
|
||||
milestone: task.type || null,
|
||||
details: task.description || null,
|
||||
editTo: task.editTo || null,
|
||||
dependingTicketId: task.dependingTicketId || null
|
||||
}));
|
||||
const tasks = data.result
|
||||
.filter((task: any) =>
|
||||
// Only include tasks assigned to the user
|
||||
Array.isArray(task.assignedTo) && task.assignedTo.includes(userId)
|
||||
)
|
||||
.map((task: any) => ({
|
||||
id: task.id.toString(),
|
||||
headline: task.headline,
|
||||
projectName: task.projectName,
|
||||
projectId: task.projectId,
|
||||
status: task.status,
|
||||
dueDate: task.dateToFinish || null,
|
||||
milestone: task.type || null,
|
||||
details: task.description || null,
|
||||
createdOn: task.dateCreated,
|
||||
editedOn: task.editedOn || null,
|
||||
assignedTo: Array.isArray(task.assignedTo) ? task.assignedTo : []
|
||||
}));
|
||||
|
||||
// Sort tasks by due date
|
||||
tasks.sort((a: any, b: any) => {
|
||||
if (!a.dueDate) return 1;
|
||||
if (!b.dueDate) return -1;
|
||||
return new Date(a.dueDate).getTime() - new Date(b.dueDate).getTime();
|
||||
// Sort tasks by creation date (oldest first)
|
||||
tasks.sort((a: Task, b: Task) => {
|
||||
const dateA = new Date(a.createdOn).getTime();
|
||||
const dateB = new Date(b.createdOn).getTime();
|
||||
return dateA - dateB;
|
||||
});
|
||||
|
||||
return NextResponse.json({ tasks });
|
||||
|
||||
107
app/components/flow.tsx
Normal file
107
app/components/flow.tsx
Normal file
@ -0,0 +1,107 @@
|
||||
'use client';
|
||||
|
||||
import { useState, useEffect } from 'react';
|
||||
|
||||
interface Task {
|
||||
id: string;
|
||||
headline: string;
|
||||
projectName: string;
|
||||
projectId: number;
|
||||
status: number;
|
||||
dueDate: string | null;
|
||||
milestone: string | null;
|
||||
details: string | null;
|
||||
createdOn: string;
|
||||
editedOn: string | null;
|
||||
assignedTo: number[];
|
||||
}
|
||||
|
||||
export default function Flow() {
|
||||
const [tasks, setTasks] = useState<Task[]>([]);
|
||||
const [loading, setLoading] = useState(false);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
const getStatusLabel = (status: number): string => {
|
||||
switch (status) {
|
||||
case 1:
|
||||
return 'New';
|
||||
case 2:
|
||||
return 'In Progress';
|
||||
case 3:
|
||||
return 'Done';
|
||||
default:
|
||||
return 'Unknown';
|
||||
}
|
||||
};
|
||||
|
||||
const getStatusColor = (status: number): string => {
|
||||
switch (status) {
|
||||
case 1:
|
||||
return 'bg-blue-100 text-blue-800 dark:bg-blue-900 dark:text-blue-300';
|
||||
case 2:
|
||||
return 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900 dark:text-yellow-300';
|
||||
case 3:
|
||||
return 'bg-green-100 text-green-800 dark:bg-green-900 dark:text-green-300';
|
||||
default:
|
||||
return 'bg-gray-100 text-gray-800 dark:bg-gray-900 dark:text-gray-300';
|
||||
}
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
const fetchTasks = async () => {
|
||||
setLoading(true);
|
||||
setError(null);
|
||||
try {
|
||||
const response = await fetch('/api/leantime/tasks');
|
||||
if (!response.ok) {
|
||||
throw new Error('Failed to fetch tasks');
|
||||
}
|
||||
const data = await response.json();
|
||||
setTasks(data);
|
||||
} catch (err) {
|
||||
setError(err instanceof Error ? err.message : 'An error occurred');
|
||||
} finally {
|
||||
setLoading(false);
|
||||
}
|
||||
};
|
||||
|
||||
fetchTasks();
|
||||
}, []);
|
||||
|
||||
if (loading) {
|
||||
return <div>Loading...</div>;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
return <div>Error: {error}</div>;
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="grid grid-cols-1 gap-4">
|
||||
{tasks.map((task) => (
|
||||
<div
|
||||
key={task.id}
|
||||
className="bg-white dark:bg-gray-800 rounded-lg shadow p-4"
|
||||
>
|
||||
<div className="flex items-start justify-between">
|
||||
<div className="flex-1">
|
||||
<h3 className="text-sm font-medium text-gray-900 dark:text-gray-100">
|
||||
{task.headline}
|
||||
</h3>
|
||||
<p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
|
||||
{task.projectName}
|
||||
</p>
|
||||
</div>
|
||||
<span
|
||||
className={`inline-flex items-center px-2.5 py-0.5 rounded-full text-xs font-medium ${getStatusColor(
|
||||
task.status
|
||||
)}`}
|
||||
>
|
||||
{getStatusLabel(task.status)}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user