Files
panel/src/lib/queries/tasks.js

403 lines
11 KiB
JavaScript

import db from "../db.js";
import { addNoteToTask } from "./notes.js";
// Get all task templates (for dropdown selection)
export function getAllTaskTemplates() {
return db
.prepare("SELECT * FROM tasks WHERE is_standard = 1 ORDER BY name ASC")
.all();
}
// Get all project tasks across all projects
export function getAllProjectTasks() {
return db
.prepare(
`
SELECT
pt.*,
COALESCE(pt.custom_task_name, t.name) as task_name,
COALESCE(pt.custom_max_wait_days, t.max_wait_days) as max_wait_days,
COALESCE(pt.custom_description, t.description) as description,
CASE
WHEN pt.task_template_id IS NOT NULL THEN 'template'
ELSE 'custom'
END as task_type,
p.project_name,
p.wp,
p.plot,
p.city,
p.address,
p.finish_date,
creator.name as created_by_name,
creator.email as created_by_email,
assignee.name as assigned_to_name,
assignee.email as assigned_to_email
FROM project_tasks pt
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
LEFT JOIN projects p ON pt.project_id = p.project_id
LEFT JOIN users creator ON pt.created_by = creator.id
LEFT JOIN users assignee ON pt.assigned_to = assignee.id
ORDER BY pt.date_added DESC
`
)
.all();
}
// Get project tasks for a specific project
export function getProjectTasks(projectId) {
return db
.prepare(
`
SELECT
pt.*,
COALESCE(pt.custom_task_name, t.name) as task_name,
COALESCE(pt.custom_max_wait_days, t.max_wait_days) as max_wait_days,
COALESCE(pt.custom_description, t.description) as description,
CASE
WHEN pt.task_template_id IS NOT NULL THEN 'template'
ELSE 'custom'
END as task_type,
creator.name as created_by_name,
creator.email as created_by_email,
assignee.name as assigned_to_name,
assignee.email as assigned_to_email
FROM project_tasks pt
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
LEFT JOIN users creator ON pt.created_by = creator.id
LEFT JOIN users assignee ON pt.assigned_to = assignee.id
WHERE pt.project_id = ?
ORDER BY pt.date_added DESC
`
)
.all(projectId);
}
// Create a new project task
export function createProjectTask(data) {
let result;
let taskName;
if (data.task_template_id) {
// Creating from template - explicitly set custom_max_wait_days to NULL so COALESCE uses template value
const stmt = db.prepare(`
INSERT INTO project_tasks (
project_id, task_template_id, custom_max_wait_days, status, priority,
created_by, assigned_to, created_at, updated_at
)
VALUES (?, ?, NULL, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
`);
result = stmt.run(
data.project_id,
data.task_template_id,
data.status || "pending",
data.priority || "normal",
data.created_by || null,
data.assigned_to || null
);
// Get the template name for the log
const templateStmt = db.prepare("SELECT name FROM tasks WHERE task_id = ?");
const template = templateStmt.get(data.task_template_id);
taskName = template?.name || "Unknown template";
} else {
// Creating custom task
const stmt = db.prepare(`
INSERT INTO project_tasks (
project_id, custom_task_name, custom_max_wait_days, custom_description,
status, priority, created_by, assigned_to, created_at, updated_at
)
VALUES (?, ?, ?, ?, ?, ?, ?, ?, CURRENT_TIMESTAMP, CURRENT_TIMESTAMP)
`);
result = stmt.run(
data.project_id,
data.custom_task_name,
data.custom_max_wait_days || 0,
data.custom_description || "",
data.status || "pending",
data.priority || "normal",
data.created_by || null,
data.assigned_to || null
);
taskName = data.custom_task_name;
}
// Add system note for task creation
if (result.lastInsertRowid) {
const priority = data.priority || "normal";
const status = data.status || "pending";
const logMessage = `Task "${taskName}" created with priority: ${priority}, status: ${status}`;
addNoteToTask(result.lastInsertRowid, logMessage, true, data.created_by);
}
return result;
}
// Update project task status
export function updateProjectTaskStatus(taskId, status, userId = null) {
// First get the current task details for logging
const getCurrentTask = db.prepare(`
SELECT
pt.status,
COALESCE(pt.custom_task_name, t.name) as task_name
FROM project_tasks pt
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
WHERE pt.id = ?
`);
const currentTask = getCurrentTask.get(taskId);
if (!currentTask) {
throw new Error(`Task with ID ${taskId} not found`);
}
const oldStatus = currentTask.status;
let stmt;
let result;
if (oldStatus === "pending" && status === "in_progress") {
// Starting a task - set date_started
stmt = db.prepare(`
UPDATE project_tasks
SET status = ?, date_started = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
`);
result = stmt.run(status, taskId);
} else if (status === "completed") {
// Completing a task - set date_completed
stmt = db.prepare(`
UPDATE project_tasks
SET status = ?, date_completed = CURRENT_TIMESTAMP, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
`);
result = stmt.run(status, taskId);
} else {
// Just updating status without changing timestamps
stmt = db.prepare(`
UPDATE project_tasks
SET status = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
`);
result = stmt.run(status, taskId);
}
// Add system note for status change (only if status actually changed)
if (result.changes > 0 && oldStatus !== status) {
const taskName = currentTask.task_name || "Unknown task";
const logMessage = `Status changed from "${oldStatus}" to "${status}"`;
addNoteToTask(taskId, logMessage, true, userId);
}
return result;
}
// Delete a project task
export function deleteProjectTask(taskId) {
// First delete all related task notes
const deleteNotesStmt = db.prepare("DELETE FROM notes WHERE task_id = ?");
deleteNotesStmt.run(taskId);
// Then delete the task itself
const deleteTaskStmt = db.prepare("DELETE FROM project_tasks WHERE id = ?");
return deleteTaskStmt.run(taskId);
}
// Get project tasks assigned to a specific user
export function getProjectTasksByAssignedUser(userId) {
return db
.prepare(
`
SELECT
pt.*,
COALESCE(pt.custom_task_name, t.name) as task_name,
COALESCE(pt.custom_max_wait_days, t.max_wait_days) as max_wait_days,
COALESCE(pt.custom_description, t.description) as description,
CASE
WHEN pt.task_template_id IS NOT NULL THEN 'template'
ELSE 'custom'
END as task_type,
p.project_name,
p.wp,
p.plot,
p.city,
p.address,
p.finish_date,
creator.name as created_by_name,
creator.email as created_by_email,
assignee.name as assigned_to_name,
assignee.email as assigned_to_email
FROM project_tasks pt
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
LEFT JOIN projects p ON pt.project_id = p.project_id
LEFT JOIN users creator ON pt.created_by = creator.id
LEFT JOIN users assignee ON pt.assigned_to = assignee.id
WHERE pt.assigned_to = ?
ORDER BY pt.date_added DESC
`
)
.all(userId);
}
// Get project tasks created by a specific user
export function getProjectTasksByCreator(userId) {
return db
.prepare(
`
SELECT
pt.*,
COALESCE(pt.custom_task_name, t.name) as task_name,
COALESCE(pt.custom_max_wait_days, t.max_wait_days) as max_wait_days,
COALESCE(pt.custom_description, t.description) as description,
CASE
WHEN pt.task_template_id IS NOT NULL THEN 'template'
ELSE 'custom'
END as task_type,
p.project_name,
p.wp,
p.plot,
p.city,
p.address,
p.finish_date,
creator.name as created_by_name,
creator.email as created_by_email,
assignee.name as assigned_to_name,
assignee.email as assigned_to_email
FROM project_tasks pt
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
LEFT JOIN projects p ON pt.project_id = p.project_id
LEFT JOIN users creator ON pt.created_by = creator.id
LEFT JOIN users assignee ON pt.assigned_to = assignee.id
WHERE pt.created_by = ?
ORDER BY pt.date_added DESC
`
)
.all(userId);
}
// Update project task assignment
export function updateProjectTaskAssignment(taskId, assignedToUserId) {
const stmt = db.prepare(`
UPDATE project_tasks
SET assigned_to = ?, updated_at = CURRENT_TIMESTAMP
WHERE id = ?
`);
return stmt.run(assignedToUserId, taskId);
}
// Get active users for task assignment (same as projects)
export function getAllUsersForTaskAssignment() {
return db
.prepare(
`
SELECT id, name, email, role
FROM users
WHERE is_active = 1
ORDER BY name ASC
`
)
.all();
}
// Update project task (general update for edit modal)
export function updateProjectTask(taskId, updates, userId = null) {
// Get current task for logging
const getCurrentTask = db.prepare(`
SELECT
pt.*,
COALESCE(pt.custom_task_name, t.name) as task_name
FROM project_tasks pt
LEFT JOIN tasks t ON pt.task_template_id = t.task_id
WHERE pt.id = ?
`);
const currentTask = getCurrentTask.get(taskId);
if (!currentTask) {
throw new Error(`Task with ID ${taskId} not found`);
}
// Build dynamic update query
const fields = [];
const values = [];
if (updates.priority !== undefined) {
fields.push("priority = ?");
values.push(updates.priority);
}
if (updates.status !== undefined) {
fields.push("status = ?");
values.push(updates.status);
// Handle status-specific timestamp updates
if (currentTask.status === "pending" && updates.status === "in_progress") {
fields.push("date_started = CURRENT_TIMESTAMP");
} else if (updates.status === "completed") {
fields.push("date_completed = CURRENT_TIMESTAMP");
}
}
if (updates.assigned_to !== undefined) {
fields.push("assigned_to = ?");
values.push(updates.assigned_to || null);
}
if (updates.date_started !== undefined) {
fields.push("date_started = ?");
values.push(updates.date_started || null);
}
// Always update the updated_at timestamp
fields.push("updated_at = CURRENT_TIMESTAMP");
values.push(taskId);
const stmt = db.prepare(`
UPDATE project_tasks
SET ${fields.join(", ")}
WHERE id = ?
`);
const result = stmt.run(...values);
// Log the update
if (userId) {
const changes = [];
if (
updates.priority !== undefined &&
updates.priority !== currentTask.priority
) {
changes.push(
`Priority: ${currentTask.priority || "None"}${
updates.priority || "None"
}`
);
}
if (updates.status !== undefined && updates.status !== currentTask.status) {
changes.push(
`Status: ${currentTask.status || "None"}${updates.status || "None"}`
);
}
if (
updates.assigned_to !== undefined &&
updates.assigned_to !== currentTask.assigned_to
) {
changes.push(`Assignment updated`);
}
if (
updates.date_started !== undefined &&
updates.date_started !== currentTask.date_started
) {
changes.push(
`Date started: ${currentTask.date_started || "None"}${
updates.date_started || "None"
}`
);
}
if (changes.length > 0) {
const logMessage = `Task updated: ${changes.join(", ")}`;
addNoteToTask(taskId, logMessage, true, userId);
}
}
return result;
}