Skip to content

Commit 17239fb

Browse files
committed
Add notification logic for task assignment and draft publication
1 parent bfef05f commit 17239fb

2 files changed

Lines changed: 104 additions & 2 deletions

File tree

‎apps/codebility/app/home/kanban/[projectId]/[id]/actions.ts‎

Lines changed: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import { revalidatePath } from "next/cache";
44
import { Task, TaskDraft } from "@/types/home/codev";
55
import { createClientServerComponent } from "@/utils/supabase/server";
6+
import { createNotificationAction } from "@/lib/actions/notification.actions";
67

78
interface CodevMember {
89
id: string;
@@ -247,8 +248,10 @@ export const updateTask = async (
247248
const rawDeadline = formData.get("deadline")?.toString();
248249
const deadline = rawDeadline === "" || rawDeadline === "null" ? null : rawDeadline;
249250

251+
const title = formData.get("title")?.toString();
252+
250253
const updateData = {
251-
title: formData.get("title")?.toString(),
254+
title: title,
252255
description: formData.get("description")?.toString(),
253256
priority: formData.get("priority")?.toString(),
254257
difficulty: formData.get("difficulty")?.toString(),
@@ -264,9 +267,10 @@ export const updateTask = async (
264267
updated_at: new Date().toISOString(),
265268
};
266269

270+
// 1. Fetch existing task to check current assignee
267271
const { data: existingTask, error: fetchError } = await supabase
268272
.from("tasks")
269-
.select("*")
273+
.select("codev_id, title, kanban_column_id")
270274
.eq("id", taskId)
271275
.single();
272276

@@ -275,6 +279,7 @@ export const updateTask = async (
275279
return { success: false, error: "Could not find task to update" };
276280
}
277281

282+
// 2. Perform the update
278283
const { error: updateError } = await supabase
279284
.from("tasks")
280285
.update({
@@ -288,6 +293,32 @@ export const updateTask = async (
288293
return { success: false, error: updateError.message };
289294
}
290295

296+
// 3. NOTIFICATION LOGIC: Trigger if assignee changed and isn't null
297+
if (codev_id && codev_id !== existingTask.codev_id) {
298+
// Get current user to avoid self-notification
299+
const { data: { user } } = await supabase.auth.getUser();
300+
301+
if (user && user.id !== codev_id) {
302+
// Fetch project info to build the action URL
303+
const { data: colData } = await supabase
304+
.from("kanban_columns")
305+
.select("board_id, kanban_boards(project_id)")
306+
.eq("id", existingTask.kanban_column_id)
307+
.single();
308+
309+
await createNotificationAction({
310+
recipientId: codev_id,
311+
title: "Task Assigned",
312+
message: `You've been assigned to: ${title || existingTask.title}`,
313+
type: "task",
314+
priority: "normal",
315+
projectId: (colData?.kanban_boards as any)?.project_id,
316+
actionUrl: `/home/kanban/${(colData?.kanban_boards as any)?.project_id}/${colData?.board_id}?taskId=${taskId}`,
317+
metadata: { taskId }
318+
});
319+
}
320+
}
321+
291322
return { success: true };
292323
} catch (error) {
293324
console.error("Update task error:", error);
@@ -989,6 +1020,25 @@ export const promoteDraft = async (
9891020
return { success: false, error: createError.message };
9901021
}
9911022

1023+
// Step 3.5: Trigger Notification if assignee exists in the draft
1024+
if (draft.codev_id) {
1025+
// Get current user to avoid self-notification
1026+
const { data: { user } } = await supabase.auth.getUser();
1027+
1028+
if (user && user.id !== draft.codev_id) {
1029+
await createNotificationAction({
1030+
recipientId: draft.codev_id,
1031+
title: "Task Assigned (from Draft)",
1032+
message: `The draft "${draft.title}" has been published and assigned to you.`,
1033+
type: "task",
1034+
priority: "normal",
1035+
projectId: draft.project_id,
1036+
actionUrl: `/home/kanban/${draft.project_id}/${draft.intended_column_id}?taskId=${newTask.id}`,
1037+
metadata: { taskId: newTask.id }
1038+
});
1039+
}
1040+
}
1041+
9921042
// Step 4: Delete the draft
9931043
const { error: deleteError } = await supabase
9941044
.from("task_drafts")
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import { createClientServerComponent } from "@/utils/supabase/server";
2+
import { createNotificationAction } from "./notification.actions";
3+
import { revalidatePath } from "next/cache";
4+
5+
interface AssignTaskParams {
6+
taskId: string;
7+
assigneeId: string;
8+
taskTitle: string;
9+
projectId: string;
10+
}
11+
12+
export async function assignTaskAction({
13+
taskId,
14+
assigneeId,
15+
taskTitle,
16+
projectId
17+
}: AssignTaskParams) {
18+
const supabase = await createClientServerComponent();
19+
20+
// 1. Update the database
21+
const { data: task, error: updateError } = await supabase.from("tasks").update({
22+
assignee_id: assigneeId,
23+
updated_at: new Date().toISOString()
24+
}).eq("id", taskId).select().single();
25+
26+
if (updateError) return { data: null, error: updateError.message };
27+
28+
// 2. Trigger the notification using your existing action
29+
// We don't "await" this if we want the UI to respond faster,
30+
// but awaiting is safer for error handling.
31+
32+
const { data: { user } } = await supabase.auth.getUser();
33+
if (user && user.id !== assigneeId) {
34+
const { error: notifyError } = await createNotificationAction({
35+
recipientId: assigneeId,
36+
title: "New Task Assigned",
37+
message: `You've been assigned to: ${taskTitle}`,
38+
type: "task", // matches your Notification type
39+
priority: "normal",
40+
projectId: projectId,
41+
actionUrl: `/dashboard/projects/${projectId}/kanban`, // Direct link to the task
42+
metadata: { taskId }
43+
});
44+
45+
if (notifyError) {
46+
console.error("Notification failed:", notifyError);
47+
}
48+
}
49+
50+
revalidatePath(`/dashboard/projects/${projectId}/kanban`);
51+
return { data: task, error: null };
52+
}

0 commit comments

Comments
 (0)