|
|
|
|
@ -282,7 +282,7 @@ export class CommandService {
|
|
|
|
|
// Listar pendientes
|
|
|
|
|
if (action === 'ver') {
|
|
|
|
|
const scopeRaw = (tokens[2] || '').toLowerCase();
|
|
|
|
|
const SCOPE_ALIASES: Record<string, 'grupo' | 'mis' | 'todos' | 'sin'> = {
|
|
|
|
|
const SCOPE_ALIASES: Record<string, 'mis' | 'todos'> = {
|
|
|
|
|
'todo': 'todos',
|
|
|
|
|
'todos': 'todos',
|
|
|
|
|
'todas': 'todos',
|
|
|
|
|
@ -304,46 +304,6 @@ export class CommandService {
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ver sin dueño del grupo actual
|
|
|
|
|
if (scope === 'sin') {
|
|
|
|
|
if (!isGroupId(context.groupId)) {
|
|
|
|
|
return [{
|
|
|
|
|
recipient: context.sender,
|
|
|
|
|
message: 'ℹ️ _Este comando se usa en grupos. Prueba:_ `/t mias`'
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
if (!GroupSyncService.isGroupActive(context.groupId)) {
|
|
|
|
|
return [{
|
|
|
|
|
recipient: context.sender,
|
|
|
|
|
message: '⚠️ _Este grupo no está activo._'
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
const items = TaskService.listGroupUnassigned(context.groupId, LIMIT);
|
|
|
|
|
const groupName = GroupSyncService.activeGroupsCache.get(context.groupId) || context.groupId;
|
|
|
|
|
|
|
|
|
|
if (items.length === 0) {
|
|
|
|
|
return [{
|
|
|
|
|
recipient: context.sender,
|
|
|
|
|
message: `_No hay tareas sin responsable en ${groupName}._`
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const rendered = items.map((t) => {
|
|
|
|
|
const isOverdue = t.due_date ? t.due_date < todayYMD : false;
|
|
|
|
|
const datePart = t.due_date ? ` — ${isOverdue ? `${ICONS.warn} ` : ''}${ICONS.date} ${formatDDMM(t.due_date)}` : '';
|
|
|
|
|
return `- ${codeId(t.id, t.display_code)} ${t.description || '(sin descripción)'}${datePart} — ${ICONS.unassigned}`;
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
const total = TaskService.countGroupUnassigned(context.groupId);
|
|
|
|
|
if (total > items.length) {
|
|
|
|
|
rendered.push(`… y ${total - items.length} más`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [{
|
|
|
|
|
recipient: context.sender,
|
|
|
|
|
message: [`${groupName} — Sin responsable`, ...rendered].join('\n')
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ver todos: "tus tareas" + "sin responsable" de grupos donde eres miembro activo (snapshot fresca)
|
|
|
|
|
if (scope === 'todos') {
|
|
|
|
|
@ -453,7 +413,7 @@ export class CommandService {
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// Si no hay snapshot fresca de membresía, mantenemos una nota instructiva mínima
|
|
|
|
|
sections.push('ℹ️ Para ver tareas sin responsable de un grupo, usa `/t ver sin` desde ese grupo.');
|
|
|
|
|
sections.push('ℹ️ Para ver tareas sin responsable, escribe por privado `/t todas` o usa `/t web`.');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -463,63 +423,6 @@ export class CommandService {
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ver grupo
|
|
|
|
|
if (scope === 'grupo') {
|
|
|
|
|
if (!isGroupId(context.groupId)) {
|
|
|
|
|
return [{
|
|
|
|
|
recipient: context.sender,
|
|
|
|
|
message: 'ℹ️ _Este comando se usa en grupos. Prueba:_ `/t mias`'
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
if (!GroupSyncService.isGroupActive(context.groupId)) {
|
|
|
|
|
return [{
|
|
|
|
|
recipient: context.sender,
|
|
|
|
|
message: '⚠️ _Este grupo no está activo._'
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
// Enforcement opcional basado en membresía si la snapshot es fresca
|
|
|
|
|
const enforce = String(process.env.GROUP_MEMBERS_ENFORCE || '').toLowerCase() === 'true';
|
|
|
|
|
const fresh = GroupSyncService.isSnapshotFresh(context.groupId);
|
|
|
|
|
if (enforce && fresh && !GroupSyncService.isUserActiveInGroup(context.sender, context.groupId)) {
|
|
|
|
|
return [{
|
|
|
|
|
recipient: context.sender,
|
|
|
|
|
message: 'No puedes ver las tareas de este grupo. Pide que te añadan si crees que es un error.'
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const items = TaskService.listGroupPending(context.groupId, LIMIT);
|
|
|
|
|
const groupName = GroupSyncService.activeGroupsCache.get(context.groupId) || context.groupId;
|
|
|
|
|
|
|
|
|
|
if (items.length === 0) {
|
|
|
|
|
return [{
|
|
|
|
|
recipient: context.sender,
|
|
|
|
|
message: italic(`No hay pendientes en ${groupName}.`)
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const rendered = await Promise.all(items.map(async (t) => {
|
|
|
|
|
const names = await Promise.all(
|
|
|
|
|
(t.assignees || []).map(async (uid) => (await ContactsService.getDisplayName(uid)) || uid)
|
|
|
|
|
);
|
|
|
|
|
const owner =
|
|
|
|
|
(t.assignees?.length || 0) === 0
|
|
|
|
|
? `${ICONS.unassigned}`
|
|
|
|
|
: `${t.assignees!.length > 1 ? '👥' : '👤'} ${names.join(', ')}`;
|
|
|
|
|
const isOverdue = t.due_date ? t.due_date < todayYMD : false;
|
|
|
|
|
const datePart = t.due_date ? ` — ${isOverdue ? `${ICONS.warn} ` : ''}${ICONS.date} ${formatDDMM(t.due_date)}` : '';
|
|
|
|
|
return `- ${codeId(t.id, t.display_code)} ${t.description || '(sin descripción)'}${datePart} — ${owner}`;
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
const total = TaskService.countGroupPending(context.groupId);
|
|
|
|
|
if (total > items.length) {
|
|
|
|
|
rendered.push(`… y ${total - items.length} más`);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return [{
|
|
|
|
|
recipient: context.sender,
|
|
|
|
|
message: [groupName, ...rendered].join('\n')
|
|
|
|
|
}];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Ver mis
|
|
|
|
|
const items = TaskService.listUserPending(context.sender, LIMIT);
|
|
|
|
|
|