Can you create me a task board which has full crud? Emphesis on this design which it must match exactly.
Develop it in src/modules/tasks
Wheert u have
src/modules/tasks/components/task-column.tsx src/modules/tasks/components/task-board.tsx src/modules/tasks/components/task-filters. ..rest components
src/modules/tasks/api/schemas
title: text('title').notNull(),
description: text('description'),
status: text('status', {
enum: ['todo', 'in-progress', 'review', 'done', 'blocked']
}).notNull().default('todo'),
priority: text('priority', {
enum: ['low', 'medium', 'high', 'critical']
}).notNull().default('medium'),
module: text('module', {
enum: ['auth', 'editor', 'graph', 'shell', 'sync', 'ui', 'db', 'core']
}),
estimatedHours: integer('estimated_hours'),
actualHours: integer('actual_hours'),
assignee: text('assignee').default('developer'),
dueDate: integer('due_date', { mode: 'timestamp' }),
completedAt: integer('completed_at', { mode: 'timestamp' }),
tags: text('tags'), // JSON string for flexibility
dependencies: text('dependencies'), // JSON string of task IDs
notes: text('notes'), // maybe json for tiptap?
export type TTask = typeof tasks.$inferSelect
export type TNewTask = typeof tasks.$inferInsert
export type TTaskStatus = 'todo' | 'in-progress' | 'review' | 'done' | 'blocked'
export type TTaskPriority = 'low' | 'medium' | 'high' | 'critical'
export type TTaskModule = 'auth' | 'editor' | 'graph' | 'shell' | 'sync' | 'ui' | 'db' | 'core'
src/modules/tasks/api/mutations/task-mutations.ts
'use server'
import { eq } from 'drizzle-orm'
import { revalidatePath } from 'next/cache'
import { db } from '@/api/db/connection'
import { tasks, type TNewTask, type TTask, type TTaskStatus } from '../schemas/task-schema'
import type { TApiResponse } from '@/shared/types/base'
export async function createTask(data: TNewTask): Promise<TApiResponse<TTask>> {
try {
const [newTask] = await db.insert(tasks).values(data).returning()
revalidatePath('/tasks')
return {
success: true,
data: newTask,
}
} catch (error) {
console.error('Failed to create task:', error)
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to create task',
}
}
}
export async function updateTask(id: string, data: Partial<TNewTask>): Promise<TApiResponse<TTask>> {
try {
const [updatedTask] = await db
.update(tasks)
.set({ ...data, updatedAt: new Date() })
.where(eq(tasks.id, id))
.returning()
if (!updatedTask) {
return {
success: false,
error: 'Task not found',
}
}
revalidatePath('/tasks')
return {
success: true,
data: updatedTask,
}
} catch (error) {
console.error('Failed to update task:', error)
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to update task',
}
}
}
export async function deleteTask(id: string): Promise<TApiResponse> {
try {
const [deletedTask] = await db.delete(tasks).where(eq(tasks.id, id)).returning()
if (!deletedTask) {
return {
success: false,
error: 'Task not found',
}
}
revalidatePath('/tasks')
return {
success: true,
}
} catch (error) {
console.error('Failed to delete task:', error)
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to delete task',
}
}
}
export async function updateTaskStatus(id: string, status: TTaskStatus): Promise<TApiResponse<TTask>> {
const completedAt = status === 'done' ? new Date() : null
try {
const [updatedTask] = await db
.update(tasks)
.set({
status,
completedAt,
updatedAt: new Date(),
})
.where(eq(tasks.id, id))
.returning()
if (!updatedTask) {
return {
success: false,
error: 'Task not found',
}
}
revalidatePath('/tasks')
return {
success: true,
data: updatedTask,
}
} catch (error) {
console.error('Failed to update task status:', error)
return {
success: false,
error: error instanceof Error ? error.message : 'Failed to update task status',
}
}
}
src/modules/tasks/api/queries/get-tasks.ts
'use server'
import { desc, eq, and, or, like } from 'drizzle-orm'
import { db } from '@/api/db/connection'
import { tasks } from '../schemas/task-schema'
import type { TTask, TTaskStatus, TTaskModule, TTaskPriority } from '../schemas/task-schema'
export async function getAllTasks(): Promise<TTask[]> {
return await db.select().from(tasks).orderBy(desc(tasks.createdAt))
}
export async function getTaskById(id: string): Promise<TTask | null> {
const result = await db.select().from(tasks).where(eq(tasks.id, id)).limit(1)
return result[0] || null
}
export async function getTasksByStatus(status: TTaskStatus): Promise<TTask[]> {
return await db.select().from(tasks).where(eq(tasks.status, status)).orderBy(desc(tasks.createdAt))
}
export async function getTasksByModule(module: TTaskModule): Promise<TTask[]> {
return await db.select().from(tasks).where(eq(tasks.module, module)).orderBy(desc(tasks.createdAt))
}
export async function getTasksByPriority(priority: TTaskPriority): Promise<TTask[]> {
return await db.select().from(tasks).where(eq(tasks.priority, priority)).orderBy(desc(tasks.createdAt))
}
export async function searchTasks(query: string): Promise<TTask[]> {
return await db
.select()
.from(tasks)
.where(
or(
like(tasks.title, `%${query}%`),
like(tasks.description, `%${query}%`),
like(tasks.notes, `%${query}%`)
)
)
.orderBy(desc(tasks.createdAt))
}
export async function getTasksWithFilters(filters: {
status?: TTaskStatus[]
module?: TTaskModule[]
priority?: TTaskPriority[]
assignee?: string
}): Promise<TTask[]> {
const conditions = []
if (filters.status?.length) {
conditions.push(or(...filters.status.map(s => eq(tasks.status, s))))
}
if (filters.module?.length) {
conditions.push(or(...filters.module.map(m => eq(tasks.module, m))))
}
if (filters.priority?.length) {
conditions.push(or(...filters.priority.map(p => eq(tasks.priority, p))))
}
if (filters.assignee) {
conditions.push(eq(tasks.assignee, filters.assignee))
}
const whereClause = conditions.length > 0 ? and(...conditions) : undefined
return await db
.select()
.from(tasks)
.where(whereClause)
.orderBy(desc(tasks.createdAt))
}
Then also /hooks, if needed .types and helpers and something else.
The main database file sits over a t src/api/db/connection.ts a nd the main schema wh ere we re-export this module schema sits at src/api/db/schema.ts
Make sure that you match the design and co lor exattly. UJse primarily bg-foreground and background to allow easy future theme switching. No zinc,neutral-900 etc.
Loading...
I see the issue! The import path is incorrect. Let me fix the file structure and import paths.
The main issue was with the import paths. I've fixed all the import statements to use the correct relative paths. The key changes:
app/tasks/page.tsx
to directly import from the component file../
paths@/src/api/db/connection
Now the task board should load properly at /tasks
. The component structure remains the same, but all the import paths are now correctly resolved.
To configure the generation, complete these steps: