Skip to content

Commit 0a74f82

Browse files
authored
Merge pull request #582 from trycompai/main
[comp] Production Deploy
2 parents 2141e41 + 28af554 commit 0a74f82

File tree

10 files changed

+895
-54
lines changed

10 files changed

+895
-54
lines changed
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
'use client';
2+
3+
import React from 'react';
4+
import { useRouter } from 'next/navigation';
5+
import { FrameworkEditorTaskTemplate } from '@prisma/client';
6+
import PageLayout from "@/app/components/PageLayout";
7+
import { DataTable } from '@/app/components/DataTable';
8+
import { Button } from '@comp/ui/button';
9+
import { PlusIcon } from 'lucide-react';
10+
import { Card, CardContent, CardHeader, CardTitle, CardDescription } from "@comp/ui/card";
11+
12+
import { getColumns } from './components/columns';
13+
import { CreateTaskDialog } from './components/CreateTaskDialog';
14+
import { EditTaskDialog } from './components/EditTaskDialog';
15+
import { DeleteTaskDialog } from './components/DeleteTaskDialog';
16+
17+
interface TasksClientPageProps {
18+
initialTasks: FrameworkEditorTaskTemplate[];
19+
}
20+
21+
export function TasksClientPage({ initialTasks }: TasksClientPageProps) {
22+
const router = useRouter();
23+
const [tasks, setTasks] = React.useState(initialTasks);
24+
const [isCreateDialogOpen, setIsCreateDialogOpen] = React.useState(false);
25+
const [editingTask, setEditingTask] = React.useState<FrameworkEditorTaskTemplate | null>(null);
26+
const [deletingTask, setDeletingTask] = React.useState<FrameworkEditorTaskTemplate | null>(null);
27+
28+
const handleTaskCreated = (newTask: FrameworkEditorTaskTemplate) => {
29+
setTasks((prevTasks) => [...prevTasks, newTask]);
30+
};
31+
32+
const handleTaskUpdated = (updatedTask: Pick<FrameworkEditorTaskTemplate, 'id' | 'name' | 'description' | 'frequency' | 'department'>) => {
33+
setTasks((prevTasks) =>
34+
prevTasks.map((task) =>
35+
task.id === updatedTask.id
36+
? { ...task, ...updatedTask }
37+
: task
38+
)
39+
);
40+
};
41+
42+
const handleTaskDeleted = (taskId: string) => {
43+
setTasks((prevTasks) => prevTasks.filter((task) => task.id !== taskId));
44+
};
45+
46+
const handleRowClick = (task: FrameworkEditorTaskTemplate) => {
47+
router.push(`/tasks/${task.id}`);
48+
};
49+
50+
const handleEditClick = (e: React.MouseEvent, task: FrameworkEditorTaskTemplate) => {
51+
e.stopPropagation();
52+
setEditingTask(task);
53+
};
54+
55+
const handleDeleteClick = (e: React.MouseEvent, task: FrameworkEditorTaskTemplate) => {
56+
e.stopPropagation();
57+
setDeletingTask(task);
58+
};
59+
60+
return (
61+
<PageLayout breadcrumbs={[{ label: "Tasks", href: "/tasks" }]}>
62+
<DataTable
63+
columns={getColumns({
64+
onEditClick: handleEditClick,
65+
onDeleteClick: handleDeleteClick,
66+
})}
67+
data={tasks}
68+
onRowClick={handleRowClick}
69+
searchQueryParamName="tasks-search"
70+
searchPlaceholder="Search tasks..."
71+
createButtonLabel="Create Task"
72+
onCreateClick={() => setIsCreateDialogOpen(true)}
73+
/>
74+
75+
<CreateTaskDialog
76+
isOpen={isCreateDialogOpen}
77+
onOpenChange={setIsCreateDialogOpen}
78+
onTaskCreated={handleTaskCreated}
79+
/>
80+
81+
{editingTask && (
82+
<EditTaskDialog
83+
isOpen={!!editingTask}
84+
onOpenChange={(isOpen) => !isOpen && setEditingTask(null)}
85+
task={editingTask}
86+
onTaskUpdated={handleTaskUpdated}
87+
/>
88+
)}
89+
90+
{deletingTask && (
91+
<DeleteTaskDialog
92+
isOpen={!!deletingTask}
93+
onOpenChange={(isOpen) => !isOpen && setDeletingTask(null)}
94+
task={deletingTask}
95+
onTaskDeleted={handleTaskDeleted}
96+
/>
97+
)}
98+
</PageLayout>
99+
);
100+
}
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
'use server';
2+
3+
import { z } from 'zod';
4+
import { db } from '@comp/db';
5+
import { revalidatePath } from 'next/cache';
6+
import { Frequency, Departments } from '@prisma/client';
7+
8+
const createTaskTemplateSchema = z.object({
9+
name: z.string().min(1, "Name is required"),
10+
description: z.string().optional(),
11+
frequency: z.nativeEnum(Frequency),
12+
department: z.nativeEnum(Departments),
13+
});
14+
15+
export type CreateTaskTemplateActionState = {
16+
success: boolean;
17+
error?: string;
18+
issues?: z.ZodIssue[];
19+
data?: any;
20+
message?: string;
21+
};
22+
23+
export async function createTaskTemplateAction(
24+
prevState: CreateTaskTemplateActionState | undefined,
25+
formData: FormData
26+
): Promise<CreateTaskTemplateActionState> {
27+
try {
28+
const rawData = {
29+
name: formData.get('name'),
30+
description: formData.get('description'),
31+
frequency: formData.get('frequency'),
32+
department: formData.get('department'),
33+
};
34+
35+
const result = createTaskTemplateSchema.safeParse(rawData);
36+
37+
if (!result.success) {
38+
return {
39+
success: false,
40+
issues: result.error.issues,
41+
};
42+
}
43+
44+
const taskTemplate = await db.frameworkEditorTaskTemplate.create({
45+
data: {
46+
name: result.data.name,
47+
description: result.data.description || '',
48+
frequency: result.data.frequency,
49+
department: result.data.department,
50+
},
51+
});
52+
53+
revalidatePath('/tasks');
54+
55+
return {
56+
success: true,
57+
data: taskTemplate,
58+
message: 'Task template created successfully',
59+
};
60+
} catch (error) {
61+
console.error('Error creating task template:', error);
62+
return {
63+
success: false,
64+
error: 'Failed to create task template',
65+
};
66+
}
67+
}
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
'use server';
2+
3+
import { z } from 'zod';
4+
import { revalidatePath } from 'next/cache';
5+
import { db } from '@comp/db';
6+
7+
const deleteTaskTemplateSchema = z.object({
8+
id: z.string(),
9+
});
10+
11+
export type DeleteTaskTemplateActionState = {
12+
success?: boolean;
13+
error?: string;
14+
message?: string;
15+
};
16+
17+
export async function deleteTaskTemplateAction(
18+
_prevState: DeleteTaskTemplateActionState | undefined,
19+
formData: FormData
20+
): Promise<DeleteTaskTemplateActionState> {
21+
try {
22+
const rawData = {
23+
id: formData.get('id'),
24+
};
25+
26+
const result = deleteTaskTemplateSchema.safeParse(rawData);
27+
28+
if (!result.success) {
29+
return {
30+
success: false,
31+
error: 'Invalid task template ID',
32+
};
33+
}
34+
35+
const { id } = result.data;
36+
37+
await db.frameworkEditorTaskTemplate.delete({
38+
where: { id },
39+
});
40+
41+
revalidatePath('/tasks');
42+
43+
return {
44+
success: true,
45+
message: 'Task Template deleted successfully!',
46+
};
47+
} catch (error) {
48+
console.error('Error deleting task template:', error);
49+
return {
50+
success: false,
51+
error: 'Failed to delete task template. Please try again.',
52+
};
53+
}
54+
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
'use server';
2+
3+
import { z } from 'zod';
4+
import { revalidatePath } from 'next/cache';
5+
import { Frequency, Departments } from '@prisma/client';
6+
import { db } from '@comp/db';
7+
8+
const updateTaskTemplateSchema = z.object({
9+
id: z.string(),
10+
name: z.string().min(1, "Name is required"),
11+
description: z.string().optional(),
12+
frequency: z.nativeEnum(Frequency),
13+
department: z.nativeEnum(Departments),
14+
});
15+
16+
export type UpdateTaskTemplateActionState = {
17+
success?: boolean;
18+
error?: string;
19+
message?: string;
20+
data?: {
21+
id: string;
22+
name: string;
23+
description: string | null;
24+
frequency: Frequency;
25+
department: Departments;
26+
};
27+
issues?: Array<{
28+
path: string[];
29+
message: string;
30+
}>;
31+
};
32+
33+
export async function updateTaskTemplateAction(
34+
_prevState: UpdateTaskTemplateActionState | undefined,
35+
formData: FormData
36+
): Promise<UpdateTaskTemplateActionState> {
37+
try {
38+
const rawData = {
39+
id: formData.get('id'),
40+
name: formData.get('name'),
41+
description: formData.get('description'),
42+
frequency: formData.get('frequency'),
43+
department: formData.get('department'),
44+
};
45+
46+
const result = updateTaskTemplateSchema.safeParse(rawData);
47+
48+
if (!result.success) {
49+
return {
50+
success: false,
51+
issues: result.error.issues.map((issue) => ({
52+
path: issue.path.map(String),
53+
message: issue.message,
54+
})),
55+
};
56+
}
57+
58+
const { id, name, description, frequency, department } = result.data;
59+
60+
const updatedTask = await db.frameworkEditorTaskTemplate.update({
61+
where: { id },
62+
data: {
63+
name,
64+
description: description || '',
65+
frequency,
66+
department,
67+
},
68+
});
69+
70+
revalidatePath('/tasks');
71+
72+
return {
73+
success: true,
74+
message: 'Task Template updated successfully!',
75+
data: updatedTask,
76+
};
77+
} catch (error) {
78+
console.error('Error updating task template:', error);
79+
return {
80+
success: false,
81+
error: 'Failed to update task template. Please try again.',
82+
};
83+
}
84+
}

0 commit comments

Comments
 (0)