Add src/app/api/tasks/route.ts
This commit is contained in:
150
src/app/api/tasks/route.ts
Normal file
150
src/app/api/tasks/route.ts
Normal file
@@ -0,0 +1,150 @@
|
||||
import { NextRequest, NextResponse } from 'next/server';
|
||||
import { getDb } from '@/server/db';
|
||||
import { tasks, priorityEnum, statusEnum, recurrenceEnum, type NewTask, type Task } from '@/server/db/schema';
|
||||
import { eq, and, or, gte, lte, asc, desc, like, ilike, sql } from 'drizzle-orm';
|
||||
import { addDays, addWeeks, addMonths, addYears } from 'date-fns';
|
||||
|
||||
export async function GET(request: NextRequest) {
|
||||
const db = getDb();
|
||||
const { searchParams } = new URL(request.url);
|
||||
|
||||
const project = searchParams.get('project');
|
||||
const search = searchParams.get('search');
|
||||
const status = searchParams.get('status');
|
||||
const priority = searchParams.get('priority');
|
||||
const dueBefore = searchParams.get('due_before');
|
||||
const dueAfter = searchParams.get('due_after');
|
||||
const completed = searchParams.get('completed');
|
||||
const sortBy = searchParams.get('sort_by') || 'due_date';
|
||||
const sortOrder = searchParams.get('sort_order') || 'asc';
|
||||
|
||||
try {
|
||||
let query = db.select().from(tasks);
|
||||
|
||||
// Build WHERE conditions
|
||||
const conditions = [];
|
||||
|
||||
if (project) {
|
||||
conditions.push(eq(tasks.projectId, project));
|
||||
}
|
||||
|
||||
if (status) {
|
||||
conditions.push(eq(tasks.status, status as any));
|
||||
}
|
||||
|
||||
if (priority) {
|
||||
conditions.push(eq(tasks.priority, priority as any));
|
||||
}
|
||||
|
||||
if (completed !== null && completed !== undefined) {
|
||||
conditions.push(eq(tasks.completed, completed === 'true'));
|
||||
}
|
||||
|
||||
if (dueBefore) {
|
||||
conditions.push(lte(tasks.dueDate, new Date(dueBefore)));
|
||||
}
|
||||
|
||||
if (dueAfter) {
|
||||
conditions.push(gte(tasks.dueDate, new Date(dueAfter)));
|
||||
}
|
||||
|
||||
if (search) {
|
||||
conditions.push(
|
||||
or(
|
||||
ilike(tasks.title, `%${search}%`),
|
||||
ilike(tasks.description, `%${search}%`)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if (conditions.length > 0) {
|
||||
query = query.where(and(...conditions));
|
||||
}
|
||||
|
||||
// Sort
|
||||
let sortColumn: any;
|
||||
switch (sortBy) {
|
||||
case 'priority':
|
||||
sortColumn = sql`CASE ${tasks.priority} WHEN 'urgent' THEN 1 WHEN 'high' THEN 2 WHEN 'medium' THEN 3 WHEN 'low' THEN 4 ELSE 5 END`;
|
||||
break;
|
||||
case 'due_date':
|
||||
default:
|
||||
sortColumn = tasks.dueDate;
|
||||
break;
|
||||
}
|
||||
|
||||
query = query.orderBy(sortOrder === 'desc' ? desc(sortColumn) : asc(sortColumn));
|
||||
|
||||
const result = await query;
|
||||
|
||||
return NextResponse.json(result);
|
||||
} catch (error) {
|
||||
console.error('Error fetching tasks:', error);
|
||||
return NextResponse.json({ error: 'Failed to fetch tasks' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const db = getDb();
|
||||
let body;
|
||||
|
||||
try {
|
||||
body = await request.json();
|
||||
} catch {
|
||||
return NextResponse.json({ error: 'Invalid JSON' }, { status: 400 });
|
||||
}
|
||||
|
||||
const {
|
||||
title,
|
||||
description = '',
|
||||
projectId,
|
||||
priority = 'medium',
|
||||
dueDate,
|
||||
status = 'todo',
|
||||
parentTaskId,
|
||||
recurrenceRule = 'none',
|
||||
recurrenceInterval = 1,
|
||||
nextOccurrence,
|
||||
} = body as NewTask & { dueDate?: string | null };
|
||||
|
||||
if (!title?.trim()) {
|
||||
return NextResponse.json({ error: 'Title is required' }, { status: 400 });
|
||||
}
|
||||
|
||||
try {
|
||||
const now = new Date();
|
||||
|
||||
// Get max sort order for this project
|
||||
const maxSort = await db
|
||||
.select({ max: tasks.sortOrder })
|
||||
.from(tasks)
|
||||
.where(eq(tasks.projectId, projectId))
|
||||
.limit(1);
|
||||
|
||||
const sortOrder = (maxSort[0]?.max ?? -1) + 1;
|
||||
|
||||
const [newTask] = await db
|
||||
.insert(tasks)
|
||||
.values({
|
||||
title: title.trim(),
|
||||
description: description?.trim() || '',
|
||||
projectId,
|
||||
priority,
|
||||
dueDate: dueDate ? new Date(dueDate) : null,
|
||||
status,
|
||||
parentTaskId,
|
||||
recurrenceRule,
|
||||
recurrenceInterval,
|
||||
nextOccurrence: nextOccurrence ? new Date(nextOccurrence) : null,
|
||||
sortOrder,
|
||||
createdAt: now,
|
||||
updatedAt: now,
|
||||
})
|
||||
.returning();
|
||||
|
||||
return NextResponse.json(newTask, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error('Error creating task:', error);
|
||||
return NextResponse.json({ error: 'Failed to create task' }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user