- number-поля теперь рендерятся как text + inputMode=numeric, чтобы браузер не округлял значения через input type=number - пробелы при вставке в number-поля удаляются - бэкенд нормализует значения number-полей в строку перед сохранением - добавлен хелпер normalizeFieldValueForStorage Closes: искажение расчётного счёта и других длинных числовых полей
84 lines
2.9 KiB
TypeScript
84 lines
2.9 KiB
TypeScript
import { Router } from 'express';
|
|
import { authenticateToken, type AuthenticatedRequest } from '../middleware/auth.middleware';
|
|
import { tenantIsolation } from '../middleware/tenant.middleware';
|
|
import { pool } from '../db';
|
|
|
|
const taskInboxHiddenRouter = Router();
|
|
|
|
// Hide a task from the current user's inbox
|
|
// Insert or ignore duplicate
|
|
taskInboxHiddenRouter.post('/api/tasks/:id/hide-inbox',
|
|
authenticateToken,
|
|
tenantIsolation,
|
|
async (req: AuthenticatedRequest, res) => {
|
|
try {
|
|
const taskId = parseInt(req.params.id);
|
|
if (isNaN(taskId)) return res.status(400).json({ success: false, error: 'Неверный ID задачи' });
|
|
const userId = req.user!.id;
|
|
const orgId = req.user!.organizationId;
|
|
|
|
await pool.query(
|
|
`INSERT INTO task_inbox_hidden (task_id, user_id, organization_id)
|
|
VALUES ($1, $2, $3)
|
|
ON CONFLICT (task_id, user_id) DO NOTHING`,
|
|
[taskId, userId, orgId]
|
|
);
|
|
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
console.error('[hide-inbox]', err);
|
|
res.status(500).json({ success: false, error: 'Ошибка при скрытии задачи' });
|
|
}
|
|
}
|
|
);
|
|
|
|
// Unhide a task for the current user
|
|
taskInboxHiddenRouter.delete('/api/tasks/:id/hide-inbox',
|
|
authenticateToken,
|
|
tenantIsolation,
|
|
async (req: AuthenticatedRequest, res) => {
|
|
try {
|
|
const taskId = parseInt(req.params.id);
|
|
if (isNaN(taskId)) return res.status(400).json({ success: false, error: 'Неверный ID задачи' });
|
|
const userId = req.user!.id;
|
|
const orgId = req.user!.organizationId;
|
|
|
|
await pool.query(
|
|
`DELETE FROM task_inbox_hidden WHERE task_id = $1 AND user_id = $2 AND organization_id = $3`,
|
|
[taskId, userId, orgId]
|
|
);
|
|
|
|
res.json({ success: true });
|
|
} catch (err) {
|
|
console.error('[unhide-inbox]', err);
|
|
res.status(500).json({ success: false, error: 'Ошибка при возврате задачи' });
|
|
}
|
|
}
|
|
);
|
|
|
|
// Check if a task is hidden for the current user
|
|
taskInboxHiddenRouter.get('/api/tasks/:id/hide-inbox',
|
|
authenticateToken,
|
|
tenantIsolation,
|
|
async (req: AuthenticatedRequest, res) => {
|
|
try {
|
|
const taskId = parseInt(req.params.id);
|
|
if (isNaN(taskId)) return res.status(400).json({ success: false, error: 'Неверный ID задачи' });
|
|
const userId = req.user!.id;
|
|
const orgId = req.user!.organizationId;
|
|
|
|
const result = await pool.query(
|
|
`SELECT 1 FROM task_inbox_hidden WHERE task_id = $1 AND user_id = $2 AND organization_id = $3 LIMIT 1`,
|
|
[taskId, userId, orgId]
|
|
);
|
|
|
|
res.json({ success: true, isHidden: result.rows.length > 0 });
|
|
} catch (err) {
|
|
console.error('[get hide-inbox]', err);
|
|
res.status(500).json({ success: false, error: 'Ошибка проверки статуса' });
|
|
}
|
|
}
|
|
);
|
|
|
|
export default taskInboxHiddenRouter;
|