From 9cff6a4126b8e63b66e6b963174923ee30fcccc9 Mon Sep 17 00:00:00 2001 From: Roberto Musso Date: Thu, 19 Feb 2026 17:02:09 +0100 Subject: [PATCH] =?UTF-8?q?feat:=20US-007=20=E2=80=94=20Task=20tRPC=20proc?= =?UTF-8?q?edures=20(CRUD=20+=20filtering)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Sonnet 4.6 --- src/main/router/index.ts | 98 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 93 insertions(+), 5 deletions(-) diff --git a/src/main/router/index.ts b/src/main/router/index.ts index f85ac3f..8858319 100644 --- a/src/main/router/index.ts +++ b/src/main/router/index.ts @@ -1,6 +1,7 @@ import { initTRPC } from '@trpc/server'; import { z } from 'zod'; -import { eq, asc, inArray, and } from 'drizzle-orm'; +import { eq, asc, inArray, and, or, like, sql } from 'drizzle-orm'; +import { alias } from 'drizzle-orm/sqlite-core'; import { getDb } from '../db'; import { clients, projects, tasks } from '../db/schema'; import { getStore } from '../store'; @@ -175,7 +176,53 @@ const tasksRouter = router({ search: z.string().optional(), orderBy: z.enum(['dueDate', 'priority', 'createdAt']).optional(), }).optional()) - .query(() => []), + .query(({ input }) => { + const db = getDb(); + const parentClients = alias(clients, 'parent_clients'); + + const searchTerm = input?.search?.trim(); + const conditions = and( + input?.projectId !== undefined ? eq(tasks.projectId, input.projectId) : undefined, + input?.status !== undefined ? eq(tasks.status, input.status) : undefined, + searchTerm + ? or( + like(tasks.title, `%${searchTerm}%`), + like(tasks.description, `%${searchTerm}%`), + ) + : undefined, + ); + + const orderByClause = + input?.orderBy === 'dueDate' + ? asc(tasks.dueDate) + : input?.orderBy === 'priority' + ? asc(sql`CASE ${tasks.priority} WHEN 'high' THEN 1 WHEN 'medium' THEN 2 WHEN 'low' THEN 3 ELSE 4 END`) + : asc(tasks.createdAt); + + return db + .select({ + id: tasks.id, + projectId: tasks.projectId, + title: tasks.title, + description: tasks.description, + status: tasks.status, + priority: tasks.priority, + assignee: tasks.assignee, + dueDate: tasks.dueDate, + createdAt: tasks.createdAt, + projectName: projects.name, + clientName: sql`CASE WHEN ${clients.parentId} IS NOT NULL THEN ${parentClients.name} ELSE ${clients.name} END`, + subClientName: sql`CASE WHEN ${clients.parentId} IS NOT NULL THEN ${clients.name} ELSE NULL END`, + }) + .from(tasks) + .leftJoin(projects, eq(tasks.projectId, projects.id)) + .leftJoin(clients, eq(projects.clientId, clients.id)) + .leftJoin(parentClients, eq(clients.parentId, parentClients.id)) + .where(conditions) + .orderBy(orderByClause) + .all(); + }), + create: publicProcedure .input(z.object({ title: z.string(), @@ -186,7 +233,23 @@ const tasksRouter = router({ dueDate: z.number().optional(), projectId: z.string().optional(), })) - .mutation(() => null), + .mutation(({ input }) => { + const id = crypto.randomUUID(); + const now = Date.now(); + getDb().insert(tasks).values({ + id, + title: input.title, + description: input.description ?? null, + status: input.status ?? 'todo', + priority: input.priority ?? 'medium', + assignee: input.assignee ?? null, + dueDate: input.dueDate ?? null, + projectId: input.projectId ?? null, + createdAt: now, + }).run(); + return { id }; + }), + update: publicProcedure .input(z.object({ id: z.string(), @@ -198,10 +261,35 @@ const tasksRouter = router({ dueDate: z.number().optional(), projectId: z.string().optional(), })) - .mutation(() => null), + .mutation(({ input }) => { + const set: Partial<{ + title: string; + description: string | null; + status: string; + priority: string; + assignee: string | null; + dueDate: number | null; + projectId: string | null; + }> = {}; + if (input.title !== undefined) set.title = input.title; + if (input.description !== undefined) set.description = input.description; + if (input.status !== undefined) set.status = input.status; + if (input.priority !== undefined) set.priority = input.priority; + if (input.assignee !== undefined) set.assignee = input.assignee; + if (input.dueDate !== undefined) set.dueDate = input.dueDate; + if (input.projectId !== undefined) set.projectId = input.projectId; + if (Object.keys(set).length > 0) { + getDb().update(tasks).set(set).where(eq(tasks.id, input.id)).run(); + } + return null; + }), + delete: publicProcedure .input(z.object({ id: z.string() })) - .mutation(() => null), + .mutation(({ input }) => { + getDb().delete(tasks).where(eq(tasks.id, input.id)).run(); + return { success: true as const }; + }), }); const checkpointsRouter = router({