diff --git a/src/bot/commands/task.ts b/src/bot/commands/task.ts index 8ac63ce..630684b 100644 --- a/src/bot/commands/task.ts +++ b/src/bot/commands/task.ts @@ -1,6 +1,7 @@ import { sendMessage } from '../utils/messaging'; import { createTask, assignTask, completeTask, getPendingTasks } from '../../services/taskService'; import { setRemindersEnabled } from '../../services/userService'; +import { normalizeUserIdentifier, extractUserFromJid } from '../../utils/userUtils'; function formatTaskList(tasks: any[]) { if (tasks.length === 0) { diff --git a/src/services/notificationService.ts b/src/services/notificationService.ts new file mode 100644 index 0000000..90214fa --- /dev/null +++ b/src/services/notificationService.ts @@ -0,0 +1,54 @@ +import { sendMessage } from '../utils/messaging'; +import { formatUserMention } from '../utils/userUtils'; +import { Task } from '../models/task'; + +export function notifyTaskCreation(task: Task) { + const creatorMention = formatUserMention(task.createdBy); + const assigneeMention = task.assignedTo ? formatUserMention(task.assignedTo) : 'ninguno'; + + // Notify creator + let message = `✅ Tarea creada:\nID: ${task.id}\nDescripción: ${task.description}`; + if (task.assignedTo) { + message += `\nAsignada a: ${assigneeMention}`; + } + if (task.dueDate) { + message += `\nFecha límite: ${task.dueDate}`; + } + sendMessage(task.createdBy, message); + + // Notify assignee if different from creator + if (task.assignedTo && task.assignedTo !== task.createdBy) { + const assigneeMessage = `📝 ${creatorMention} te ha asignado una nueva tarea:\n` + + `ID: ${task.id}\nDescripción: ${task.description}` + + (task.dueDate ? `\nFecha límite: ${task.dueDate}` : ''); + sendMessage(task.assignedTo, assigneeMessage); + } +} + +export function notifyTaskAssignment(task: Task, assignedBy: string) { + const assignerMention = formatUserMention(assignedBy); + const assigneeMention = formatUserMention(task.assignedTo); + + // Notify assigner + sendMessage(assignedBy, `✅ Tarea ${task.id} asignada a ${assigneeMention}`); + + // Notify assignee + const assigneeMessage = `📝 ${assignerMention} te ha asignado la tarea:\n` + + `ID: ${task.id}\nDescripción: ${task.description}` + + (task.dueDate ? `\nFecha límite: ${task.dueDate}` : ''); + sendMessage(task.assignedTo, assigneeMessage); +} + +export function notifyTaskCompletion(task: Task, completedBy: string) { + const completerMention = formatUserMention(completedBy); + + // Notify completer + sendMessage(completedBy, `✅ Tarea completada:\nID: ${task.id}\nDescripción: ${task.description}`); + + // Notify creator if different from completer + if (task.createdBy && task.createdBy !== completedBy) { + const creatorMessage = `✅ ${completerMention} ha completado la tarea:\n` + + `ID: ${task.id}\nDescripción: ${task.description}`; + sendMessage(task.createdBy, creatorMessage); + } +} diff --git a/src/services/taskService.ts b/src/services/taskService.ts index eb32b63..6130392 100644 --- a/src/services/taskService.ts +++ b/src/services/taskService.ts @@ -1,7 +1,11 @@ import { query, execute } from '../database/db'; +import { normalizeUserIdentifier } from '../utils/userUtils'; +import { notifyTaskCreation, notifyTaskAssignment, notifyTaskCompletion } from './notificationService'; // Create a new task export function createTask(sender: string, params: CreateTaskParams) { + const createdBy = normalizeUserIdentifier(sender); + const assignedTo = params.assignedTo ? normalizeUserIdentifier(params.assignedTo) : null; if (!params.description || params.description.trim().length < 3) { throw new Error('La descripción de la tarea debe tener al menos 3 caracteres'); } @@ -12,13 +16,16 @@ export function createTask(sender: string, params: CreateTaskParams) { const result = execute( 'INSERT INTO tasks (description, created_by, assigned_to, due_date, completed) VALUES (?, ?, ?, ?, ?)', - [params.description.trim(), sender, params.assignedTo || null, params.dueDate || null, false] + [params.description.trim(), createdBy, assignedTo, params.dueDate || null, false] ); const task = getTaskById(result.lastInsertRowid); if (!task) { throw new Error('Error al crear la tarea'); } + + // Notify relevant users + notifyTaskCreation(task); return task; } diff --git a/src/utils/userUtils.ts b/src/utils/userUtils.ts new file mode 100644 index 0000000..f26c867 --- /dev/null +++ b/src/utils/userUtils.ts @@ -0,0 +1,24 @@ +export function normalizeUserIdentifier(input: string): string { + // Remove @ prefix if present + const cleanInput = input.startsWith('@') ? input.slice(1) : input; + + // Remove any non-numeric characters + const phoneNumber = cleanInput.replace(/\D/g, ''); + + // Validate phone number length + if (phoneNumber.length < 8 || phoneNumber.length > 15) { + throw new Error('Número de teléfono inválido'); + } + + return `@${phoneNumber}`; +} + +export function extractUserFromJid(jid: string): string { + // Extract phone number from JID (format: 12345678@s.whatsapp.net) + const phoneNumber = jid.split('@')[0]; + return normalizeUserIdentifier(phoneNumber); +} + +export function formatUserMention(phoneNumber: string): string { + return `@${phoneNumber.replace('@', '')}`; +}