Refactor Card, Managers, Schedule, and SelectUser components to enhance functionality and UI; integrate manager selection logic, improve session handling, and add loading states for better user experience.
This commit is contained in:
@@ -9,6 +9,14 @@ const router = Router();
|
||||
router.post("/", async (req, res) => {
|
||||
const { companyId, username, name, role, buildIds } = req.body;
|
||||
|
||||
if (res.locals.user.role !== "admin") {
|
||||
return res.status(403).json({ error: "Только администратор может добавлять менеджеров" });
|
||||
}
|
||||
|
||||
if (companyId != res.locals.user.companyId) {
|
||||
return res.status(403).json({ error: "Access denied" });
|
||||
}
|
||||
|
||||
try {
|
||||
const password = generate({
|
||||
length: 8,
|
||||
@@ -49,9 +57,10 @@ router.post("/", async (req, res) => {
|
||||
await transporter.sendMail({
|
||||
from: "stream@graff.tech", // sender address
|
||||
to: username, // list of receivers
|
||||
subject: "Данные аккаунта - stream.graff.tech", // Subject line
|
||||
subject: "Данные аккаунта - crm.stream.graff.tech", // Subject line
|
||||
html: `<div>
|
||||
Пароль для входа в аккаунт: <b>${password}</b>
|
||||
Пароль для входа в аккаунт: <b>${password}</b><br>
|
||||
Ссылка для входа: <a href="https://crm.stream.graff.tech/" target="_blank">https://crm.stream.graff.tech/</a>
|
||||
</div>`,
|
||||
});
|
||||
} catch (error) {
|
||||
|
||||
+115
-44
@@ -4,6 +4,7 @@ import Company from "../models/Company.js";
|
||||
import ScheduledSession from "../models/ScheduledSession.js";
|
||||
import Schedule from "../models/Schedule.js";
|
||||
import User from "../models/User.js";
|
||||
import mongoose from "mongoose";
|
||||
|
||||
const router = Router();
|
||||
|
||||
@@ -15,8 +16,7 @@ const router = Router();
|
||||
|
||||
router.get("/:companyId", async (req, res) => {
|
||||
if (req.params.companyId != res.locals.user.companyId) {
|
||||
res.json({ error: "Access denied" });
|
||||
return;
|
||||
return res.status(403).json({ error: "Access denied" });
|
||||
}
|
||||
|
||||
const company = await Company.findById(req.params.companyId);
|
||||
@@ -26,8 +26,7 @@ router.get("/:companyId", async (req, res) => {
|
||||
|
||||
router.put("/:companyId", async (req, res) => {
|
||||
if (req.params.companyId != res.locals.user.companyId) {
|
||||
res.json({ error: "Access denied" });
|
||||
return;
|
||||
return res.status(403).json({ error: "Access denied" });
|
||||
}
|
||||
|
||||
const company = await Company.findByIdAndUpdate(
|
||||
@@ -43,8 +42,7 @@ router.put("/:companyId", async (req, res) => {
|
||||
|
||||
router.get("/:companyId/builds", async (req, res) => {
|
||||
if (req.params.companyId != res.locals.user.companyId) {
|
||||
res.json({ error: "Access denied" });
|
||||
return;
|
||||
return res.status(403).json({ error: "Access denied" });
|
||||
}
|
||||
|
||||
const company: any = await Company.findById(req.params.companyId).populate(
|
||||
@@ -57,8 +55,7 @@ router.get("/:companyId/builds", async (req, res) => {
|
||||
|
||||
router.get("/:companyId/users", async (req, res) => {
|
||||
if (req.params.companyId != res.locals.user.companyId) {
|
||||
res.json({ error: "Access denied" });
|
||||
return;
|
||||
return res.status(403).json({ error: "Access denied" });
|
||||
}
|
||||
|
||||
const company: any = await Company.findById(req.params.companyId).populate(
|
||||
@@ -71,8 +68,7 @@ router.get("/:companyId/users", async (req, res) => {
|
||||
|
||||
router.get("/:companyId/builds/:buildId/users", async (req, res) => {
|
||||
if (req.params.companyId != res.locals.user.companyId) {
|
||||
res.json({ error: "Access denied" });
|
||||
return;
|
||||
return res.status(403).json({ error: "Access denied" });
|
||||
}
|
||||
|
||||
const buildUsers: any = await User.find({
|
||||
@@ -91,8 +87,7 @@ router.get("/:companyId/builds/:buildId/users", async (req, res) => {
|
||||
|
||||
router.get("/:companyId/scheduledSessions", async (req, res) => {
|
||||
if (req.params.companyId != res.locals.user.companyId) {
|
||||
res.json({ error: "Access denied" });
|
||||
return;
|
||||
return res.status(403).json({ error: "Access denied" });
|
||||
}
|
||||
|
||||
const { startDate, endDate } = req.query;
|
||||
@@ -117,71 +112,147 @@ router.get("/:companyId/scheduledSessions", async (req, res) => {
|
||||
res.json(scheduledSessions);
|
||||
});
|
||||
|
||||
router.get(
|
||||
"/:companyId/builds/:buildId/scheduledSessions/:scheduledSessionId/availableManagers",
|
||||
async (req, res) => {
|
||||
if (req.params.companyId != res.locals.user.companyId) {
|
||||
return res.status(403).json({ error: "Access denied" });
|
||||
}
|
||||
|
||||
const { companyId, buildId, scheduledSessionId } = req.params;
|
||||
const { startAt } = req.query as { startAt: string };
|
||||
|
||||
try {
|
||||
const startAtDate = parseISO(startAt);
|
||||
|
||||
// All managers of this company assigned to this build
|
||||
const buildManagers = await User.find({
|
||||
companyId,
|
||||
role: "manager",
|
||||
buildIds: new mongoose.Types.ObjectId(buildId),
|
||||
});
|
||||
|
||||
// Find managers already busy at this time (excluding current session)
|
||||
const busySessions = await ScheduledSession.find({
|
||||
_id: { $ne: new mongoose.Types.ObjectId(scheduledSessionId) },
|
||||
userId: { $in: buildManagers.map((m) => m._id) },
|
||||
startAt: startAtDate,
|
||||
});
|
||||
|
||||
const busyManagerIds = new Set(
|
||||
busySessions.map((s) => s.userId?.toString())
|
||||
);
|
||||
|
||||
const available = buildManagers
|
||||
.filter((m) => !busyManagerIds.has(m._id.toString()))
|
||||
.map((m) => m._id.toString());
|
||||
|
||||
res.json(available);
|
||||
} catch (error) {
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.put(
|
||||
"/:companyId/scheduledSessions/:scheduledSessionId",
|
||||
async (req, res) => {
|
||||
if (req.params.companyId != res.locals.user.companyId) {
|
||||
res.json({ error: "Access denied" });
|
||||
return;
|
||||
return res.status(403).json({ error: "Access denied" });
|
||||
}
|
||||
|
||||
const { companyId, scheduledSessionId } = req.params;
|
||||
const { userId: newManagerId } = req.body;
|
||||
|
||||
try {
|
||||
const scheduledSession = await ScheduledSession.findById(
|
||||
req.params.scheduledSessionId
|
||||
);
|
||||
const scheduledSession = await ScheduledSession.findById(scheduledSessionId);
|
||||
|
||||
if (!scheduledSession) {
|
||||
return res.status(404).json({ error: "Сессия не найдена" });
|
||||
}
|
||||
|
||||
if (scheduledSession.companyId.toString() !== companyId) {
|
||||
return res.status(403).json({ error: "Access denied" });
|
||||
}
|
||||
|
||||
if (res.locals.user.role === "manager") {
|
||||
const currentUserId = res.locals.user._id.toString();
|
||||
if (newManagerId !== null && newManagerId !== currentUserId) {
|
||||
return res.status(403).json({
|
||||
error: "Менеджер может назначать только себя на сессию",
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
const scheduledSessionAtSameTime = await ScheduledSession.findOne({
|
||||
startAt: scheduledSession?.startAt,
|
||||
userId: req.body.userId,
|
||||
startAt: scheduledSession.startAt,
|
||||
userId: newManagerId,
|
||||
});
|
||||
|
||||
if (scheduledSessionAtSameTime && req.body.userId !== null) {
|
||||
if (scheduledSessionAtSameTime && newManagerId !== null) {
|
||||
await ScheduledSession.updateMany(
|
||||
{
|
||||
userId: req.body.userId,
|
||||
startAt: scheduledSession?.startAt,
|
||||
userId: newManagerId,
|
||||
startAt: scheduledSession.startAt,
|
||||
},
|
||||
{
|
||||
userId: null,
|
||||
}
|
||||
{ userId: null }
|
||||
);
|
||||
|
||||
await ScheduledSession.findByIdAndUpdate(
|
||||
req.params.scheduledSessionId,
|
||||
{
|
||||
userId: req.body.userId,
|
||||
}
|
||||
scheduledSessionId,
|
||||
{ userId: newManagerId },
|
||||
{ new: true }
|
||||
);
|
||||
res.json({ error: "Scheduled session at same time" });
|
||||
return;
|
||||
return res.json({ error: "Scheduled session at same time" });
|
||||
}
|
||||
|
||||
const updatedScheduledSession = await ScheduledSession.findByIdAndUpdate(
|
||||
req.params.scheduledSessionId,
|
||||
req.body,
|
||||
{
|
||||
new: true,
|
||||
upsert: true,
|
||||
}
|
||||
scheduledSessionId,
|
||||
{ userId: newManagerId },
|
||||
{ new: true }
|
||||
);
|
||||
|
||||
res.json(updatedScheduledSession);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
res.json({ error });
|
||||
res.status(500).json({ error: error.message });
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
router.get("/:companyId/users", async (req, res) => {
|
||||
try {
|
||||
const companyId = req.params.companyId;
|
||||
const users = await User.find({ companyId });
|
||||
router.delete("/:companyId/users/:userId", async (req, res) => {
|
||||
if (res.locals.user.role !== "admin") {
|
||||
return res.status(403).json({ error: "Только администратор может удалять менеджеров" });
|
||||
}
|
||||
|
||||
return res.json(users);
|
||||
if (req.params.companyId != res.locals.user.companyId) {
|
||||
return res.status(403).json({ error: "Access denied" });
|
||||
}
|
||||
|
||||
const { companyId, userId } = req.params;
|
||||
|
||||
try {
|
||||
const user = await User.findOne({ _id: userId, companyId });
|
||||
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: "Пользователь не найден" });
|
||||
}
|
||||
|
||||
if (user.role === "admin") {
|
||||
return res.status(403).json({ error: "Нельзя удалить администратора" });
|
||||
}
|
||||
|
||||
await ScheduledSession.updateMany(
|
||||
{ companyId, userId: new mongoose.Types.ObjectId(userId) },
|
||||
{ userId: null }
|
||||
);
|
||||
|
||||
await User.findByIdAndRemove(userId);
|
||||
|
||||
res.json({ success: true });
|
||||
} catch (error) {
|
||||
return res.json({ error: (error as Error).message });
|
||||
res.status(500).json({ error: (error as Error).message });
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@ router.post("/", async (req, res) => {
|
||||
await transporter.sendMail({
|
||||
from: "stream@graff.tech", // sender address
|
||||
to: username, // list of receivers
|
||||
subject: "Сброс пароля - stream.graff.tech", // Subject line
|
||||
subject: "Сброс пароля - crm.stream.graff.tech", // Subject line
|
||||
html: `<div>
|
||||
Ссылка для сброса пароля: <a href="${url}" target="_blank">${url}</a>
|
||||
</div>`,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { Router } from "express";
|
||||
import User from "../models/User.js";
|
||||
// import User from "../models/User.js";
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.get("/", async (req, res) => {
|
||||
try {
|
||||
const result = await User.find(req.query);
|
||||
const companyId = res.locals.user.companyId;
|
||||
const result = await User.find({ companyId, ...req.query });
|
||||
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
@@ -16,7 +16,15 @@ router.get("/", async (req, res) => {
|
||||
|
||||
router.get("/:id", async (req, res) => {
|
||||
try {
|
||||
const result = await User.findById(req.params);
|
||||
const result = await User.findById(req.params.id);
|
||||
|
||||
if (!result) {
|
||||
return res.status(404).json({ error: "Пользователь не найден" });
|
||||
}
|
||||
|
||||
if (result.companyId.toString() !== res.locals.user.companyId) {
|
||||
return res.status(403).json({ error: "Access denied" });
|
||||
}
|
||||
|
||||
res.json(result);
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user