Changes
Co-authored-by: renee-png <262607627+renee-png@users.noreply.github.com>
This commit is contained in:
co-authored by
renee-png
parent
e4b17c1f8c
commit
2aafeb6d6b
@@ -0,0 +1,151 @@
|
||||
import { supabase } from "@/integrations/supabase/client";
|
||||
import { addDays, format } from "date-fns";
|
||||
|
||||
/**
|
||||
* After a task is marked complete, spawn the next task from its workflow
|
||||
* template (if any). Sequential mode: only one task at a time per chain.
|
||||
*
|
||||
* Returns the new task id, or null if nothing was spawned.
|
||||
*/
|
||||
export async function spawnNextWorkflowTask(taskId: string): Promise<string | null> {
|
||||
// Pull the just-completed task's workflow context
|
||||
const { data: task } = await supabase
|
||||
.from("tasks")
|
||||
.select("id, case_id, workflow_template_id, template_task_id, created_by, completed_at")
|
||||
.eq("id", taskId)
|
||||
.maybeSingle();
|
||||
|
||||
if (!task?.workflow_template_id || !task.template_task_id) return null;
|
||||
|
||||
// Find current template task to know its sort_order
|
||||
const { data: currentTpl } = await supabase
|
||||
.from("workflow_template_tasks")
|
||||
.select("id, sort_order")
|
||||
.eq("id", task.template_task_id)
|
||||
.maybeSingle();
|
||||
if (!currentTpl) return null;
|
||||
|
||||
// Find the next template task (smallest sort_order greater than current)
|
||||
const { data: nextTpl } = await supabase
|
||||
.from("workflow_template_tasks")
|
||||
.select("*")
|
||||
.eq("template_id", task.workflow_template_id)
|
||||
.gt("sort_order", currentTpl.sort_order)
|
||||
.order("sort_order", { ascending: true })
|
||||
.limit(1)
|
||||
.maybeSingle();
|
||||
|
||||
if (!nextTpl) return null;
|
||||
|
||||
// Don't double-spawn: skip if there's already a task in this chain for that template_task_id
|
||||
const { data: existing } = await supabase
|
||||
.from("tasks")
|
||||
.select("id")
|
||||
.eq("workflow_template_id", task.workflow_template_id)
|
||||
.eq("template_task_id", nextTpl.id)
|
||||
.eq("case_id", task.case_id ?? "")
|
||||
.maybeSingle();
|
||||
if (existing) return existing.id;
|
||||
|
||||
const baseDate = task.completed_at ? new Date(task.completed_at) : new Date();
|
||||
const dueDate = format(addDays(baseDate, nextTpl.days_from_start ?? 0), "yyyy-MM-dd");
|
||||
|
||||
const { data: created, error } = await supabase
|
||||
.from("tasks")
|
||||
.insert({
|
||||
title: nextTpl.title,
|
||||
description: nextTpl.description,
|
||||
priority: nextTpl.priority,
|
||||
due_date: dueDate,
|
||||
case_id: task.case_id,
|
||||
workflow_template_id: task.workflow_template_id,
|
||||
template_task_id: nextTpl.id,
|
||||
created_by: task.created_by,
|
||||
sort_order: nextTpl.sort_order,
|
||||
})
|
||||
.select("id")
|
||||
.single();
|
||||
|
||||
if (error || !created) return null;
|
||||
|
||||
if (nextTpl.default_assignee_id) {
|
||||
await supabase.from("task_assignees").insert({
|
||||
task_id: created.id,
|
||||
user_id: nextTpl.default_assignee_id,
|
||||
assigned_by: task.created_by,
|
||||
});
|
||||
}
|
||||
await supabase.from("task_history").insert({
|
||||
task_id: created.id,
|
||||
actor_id: task.created_by,
|
||||
event: "spawned_from_workflow",
|
||||
detail: { template_id: task.workflow_template_id, after_task: taskId },
|
||||
});
|
||||
|
||||
return created.id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Same idea for collection_tasks (collections workflow chain).
|
||||
*/
|
||||
export async function spawnNextCollectionWorkflowTask(
|
||||
collectionTaskId: string,
|
||||
): Promise<string | null> {
|
||||
const { data: ct } = await supabase
|
||||
.from("collection_tasks")
|
||||
.select(
|
||||
"id, collection_id, workflow_template_id, template_task_id, created_by, done_at, assignee_id",
|
||||
)
|
||||
.eq("id", collectionTaskId)
|
||||
.maybeSingle();
|
||||
|
||||
if (!ct?.workflow_template_id || !ct.template_task_id) return null;
|
||||
|
||||
const { data: currentTpl } = await supabase
|
||||
.from("workflow_template_tasks")
|
||||
.select("id, sort_order")
|
||||
.eq("id", ct.template_task_id)
|
||||
.maybeSingle();
|
||||
if (!currentTpl) return null;
|
||||
|
||||
const { data: nextTpl } = await supabase
|
||||
.from("workflow_template_tasks")
|
||||
.select("*")
|
||||
.eq("template_id", ct.workflow_template_id)
|
||||
.gt("sort_order", currentTpl.sort_order)
|
||||
.order("sort_order", { ascending: true })
|
||||
.limit(1)
|
||||
.maybeSingle();
|
||||
|
||||
if (!nextTpl) return null;
|
||||
|
||||
const { data: existing } = await supabase
|
||||
.from("collection_tasks")
|
||||
.select("id")
|
||||
.eq("collection_id", ct.collection_id)
|
||||
.eq("workflow_template_id", ct.workflow_template_id)
|
||||
.eq("template_task_id", nextTpl.id)
|
||||
.maybeSingle();
|
||||
if (existing) return existing.id;
|
||||
|
||||
const baseDate = ct.done_at ? new Date(ct.done_at) : new Date();
|
||||
const dueDate = format(addDays(baseDate, nextTpl.days_from_start ?? 0), "yyyy-MM-dd");
|
||||
|
||||
const { data: created, error } = await supabase
|
||||
.from("collection_tasks")
|
||||
.insert({
|
||||
collection_id: ct.collection_id,
|
||||
title: nextTpl.title,
|
||||
due_date: dueDate,
|
||||
sort_order: nextTpl.sort_order,
|
||||
assignee_id: nextTpl.default_assignee_id ?? null,
|
||||
workflow_template_id: ct.workflow_template_id,
|
||||
template_task_id: nextTpl.id,
|
||||
created_by: ct.created_by,
|
||||
})
|
||||
.select("id")
|
||||
.single();
|
||||
|
||||
if (error || !created) return null;
|
||||
return created.id;
|
||||
}
|
||||
Reference in New Issue
Block a user