feat: Group chat and push notifications
- Add group chat tables (chat_groups, chat_group_members, group_messages) - Add push subscriptions table for web push notifications - Add group service, controller, routes - Add push service, controller, routes - Integrate push notifications with todos, messages, group messages Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -3,6 +3,8 @@ import { todos, todoUsers, notes, projects, companies, users } from '../db/schem
|
||||
import { eq, desc, ilike, or, and, inArray } from 'drizzle-orm';
|
||||
import { NotFoundError } from '../utils/errors.js';
|
||||
import { getAccessibleResourceIds } from '../middlewares/auth/resourceAccessMiddleware.js';
|
||||
import { sendPushNotificationToUsers } from './push.service.js';
|
||||
import { logger } from '../utils/logger.js';
|
||||
|
||||
/**
|
||||
* Get all todos
|
||||
@@ -217,6 +219,25 @@ export const createTodo = async (userId, data) => {
|
||||
});
|
||||
}
|
||||
|
||||
// Send push notifications to assigned users (excluding creator)
|
||||
if (assignedUserIds && Array.isArray(assignedUserIds) && assignedUserIds.length > 0) {
|
||||
try {
|
||||
await sendPushNotificationToUsers(
|
||||
assignedUserIds,
|
||||
{
|
||||
title: 'Nová úloha',
|
||||
body: `Bola vám priradená úloha: ${title}`,
|
||||
icon: '/icon-192.png',
|
||||
badge: '/badge-72.png',
|
||||
data: { url: '/todos', todoId: newTodo.id },
|
||||
},
|
||||
userId // exclude creator
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error('Failed to send push notifications for new todo', error);
|
||||
}
|
||||
}
|
||||
|
||||
return newTodo;
|
||||
};
|
||||
|
||||
@@ -224,8 +245,9 @@ export const createTodo = async (userId, data) => {
|
||||
* Update todo
|
||||
* @param {string} todoId - ID of todo to update
|
||||
* @param {object} data - Updated data including assignedUserIds array
|
||||
* @param {string} updatedByUserId - ID of user making the update (for notifications)
|
||||
*/
|
||||
export const updateTodo = async (todoId, data) => {
|
||||
export const updateTodo = async (todoId, data, updatedByUserId = null) => {
|
||||
const todo = await getTodoById(todoId);
|
||||
|
||||
const { title, description, projectId, companyId, assignedUserIds, status, priority, dueDate } = data;
|
||||
@@ -294,6 +316,13 @@ export const updateTodo = async (todoId, data) => {
|
||||
|
||||
// Update assigned users if provided
|
||||
if (assignedUserIds !== undefined) {
|
||||
// Get existing assigned users before deleting
|
||||
const existingAssignments = await db
|
||||
.select({ userId: todoUsers.userId })
|
||||
.from(todoUsers)
|
||||
.where(eq(todoUsers.todoId, todoId));
|
||||
const existingUserIds = existingAssignments.map(a => a.userId);
|
||||
|
||||
// Delete existing assignments
|
||||
await db.delete(todoUsers).where(eq(todoUsers.todoId, todoId));
|
||||
|
||||
@@ -302,10 +331,34 @@ export const updateTodo = async (todoId, data) => {
|
||||
const todoUserInserts = assignedUserIds.map((userId) => ({
|
||||
todoId: todoId,
|
||||
userId: userId,
|
||||
assignedBy: null, // We don't track who made the update
|
||||
assignedBy: updatedByUserId,
|
||||
}));
|
||||
|
||||
await db.insert(todoUsers).values(todoUserInserts);
|
||||
|
||||
// Find newly assigned users (not in existing list)
|
||||
const newlyAssignedUserIds = assignedUserIds.filter(
|
||||
id => !existingUserIds.includes(id)
|
||||
);
|
||||
|
||||
// Send push notifications to newly assigned users
|
||||
if (newlyAssignedUserIds.length > 0) {
|
||||
try {
|
||||
await sendPushNotificationToUsers(
|
||||
newlyAssignedUserIds,
|
||||
{
|
||||
title: 'Priradená úloha',
|
||||
body: `Bola vám priradená úloha: ${updated.title}`,
|
||||
icon: '/icon-192.png',
|
||||
badge: '/badge-72.png',
|
||||
data: { url: '/todos', todoId: todoId },
|
||||
},
|
||||
updatedByUserId // exclude user making the change
|
||||
);
|
||||
} catch (error) {
|
||||
logger.error('Failed to send push notifications for updated todo', error);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user