// Task Team — Groups CRUD — 2026-03-29 async function groupRoutes(app) { app.get('/groups', async (req) => { const lang = req.query.lang; const { rows } = await app.db.query( 'SELECT * FROM task_groups ORDER BY order_index ASC' ); const data = rows.map(row => { if (lang && row.names && row.names[lang]) { return { ...row, name: row.names[lang] }; } return row; }); return { data }; }); app.get('/groups/:id', async (req) => { const lang = req.query.lang; const { rows } = await app.db.query('SELECT * FROM task_groups WHERE id = $1', [req.params.id]); if (!rows.length) throw { statusCode: 404, message: 'Group not found' }; const row = rows[0]; if (lang && row.names && row.names[lang]) { row.name = row.names[lang]; } return { data: row }; }); app.post('/groups', async (req) => { const { name, color, icon, order_index, time_zones, user_id } = req.body; const { rows } = await app.db.query( 'INSERT INTO task_groups (user_id, name, color, icon, order_index, time_zones) VALUES ($1,$2,$3,$4,$5,$6) RETURNING *', [user_id, name, color, icon || '', order_index || 0, JSON.stringify(time_zones || [])] ); return { data: rows[0] }; }); app.put('/groups/:id', async (req) => { const { name, color, icon, order_index, time_zones, locations } = req.body; const { rows } = await app.db.query( `UPDATE task_groups SET name=COALESCE($1,name), color=COALESCE($2,color), icon=COALESCE($3,icon), order_index=COALESCE($4,order_index), time_zones=COALESCE($5,time_zones), locations=COALESCE($6,locations), updated_at=NOW() WHERE id=$7 RETURNING *`, [name, color, icon, order_index, time_zones ? JSON.stringify(time_zones) : null, locations ? JSON.stringify(locations) : null, req.params.id] ); if (!rows.length) throw { statusCode: 404, message: 'Group not found' }; return { data: rows[0] }; }); app.delete('/groups/:id', async (req) => { const { rowCount } = await app.db.query('DELETE FROM task_groups WHERE id = $1', [req.params.id]); if (!rowCount) throw { statusCode: 404, message: 'Group not found' }; return { status: 'deleted' }; }); app.put('/groups/reorder', async (req) => { const { order } = req.body; // [{id, order_index}] const client = await app.db.connect(); try { await client.query('BEGIN'); for (const item of order) { await client.query('UPDATE task_groups SET order_index=$1, updated_at=NOW() WHERE id=$2', [item.order_index, item.id]); } await client.query('COMMIT'); } catch (e) { await client.query('ROLLBACK'); throw e; } finally { client.release(); } return { status: 'ok' }; }); // Update time zones for a group app.put('/groups/:id/timezones', async (req) => { const { time_zones } = req.body; if (!Array.isArray(time_zones)) { throw { statusCode: 400, message: 'time_zones must be an array of [{days, from, to}]' }; } for (const tz of time_zones) { if (!Array.isArray(tz.days) || !tz.from || !tz.to) { throw { statusCode: 400, message: 'Each timezone must have days (array), from (HH:MM), to (HH:MM)' }; } } const { rows } = await app.db.query( 'UPDATE task_groups SET time_zones = $1, updated_at = NOW() WHERE id = $2 RETURNING *', [JSON.stringify(time_zones), req.params.id] ); if (!rows.length) throw { statusCode: 404, message: 'Group not found' }; return { data: rows[0] }; }); // Update GPS locations for a group app.put('/groups/:id/locations', async (req) => { const { locations } = req.body; if (!Array.isArray(locations)) { throw { statusCode: 400, message: 'locations must be an array of [{name, lat, lng, radius_m}]' }; } for (const loc of locations) { if (!loc.name || loc.lat === undefined || loc.lng === undefined) { throw { statusCode: 400, message: 'Each location must have name, lat, lng' }; } if (typeof loc.lat !== 'number' || typeof loc.lng !== 'number') { throw { statusCode: 400, message: 'lat and lng must be numbers' }; } } const { rows } = await app.db.query( 'UPDATE task_groups SET locations = $1, updated_at = NOW() WHERE id = $2 RETURNING *', [JSON.stringify(locations), req.params.id] ); if (!rows.length) throw { statusCode: 404, message: 'Group not found' }; return { data: rows[0] }; }); // Combined schedule: time zones + locations for a group app.get('/groups/:id/schedule', async (req) => { const { rows } = await app.db.query( 'SELECT id, name, time_zones, locations FROM task_groups WHERE id = $1', [req.params.id] ); if (!rows.length) throw { statusCode: 404, message: 'Group not found' }; const g = rows[0]; return { data: { group_id: g.id, group_name: g.name, time_zones: g.time_zones || [], locations: g.locations || [], summary: { tz_count: (g.time_zones || []).length, loc_count: (g.locations || []).length } } }; }); } module.exports = groupRoutes;