feat: employee management — add/delete users from Members page
- Backend: POST /api/auth/users (create user), DELETE /api/auth/users/:id (delete user, unassign tasks) - Frontend API: apiCreateUser, apiDeleteUser - MembersPage: working Add Employee modal (name/email/password/role/dept), delete button with confirmation - Only CEO/CTO/Manager roles see management controls - CSS: btn-danger, btn-danger-sm styles
This commit is contained in:
@@ -76,4 +76,59 @@ router.get('/users', async (_req, res) => {
|
||||
}
|
||||
});
|
||||
|
||||
// POST /api/auth/users — Admin-create a new user (manager/cto/ceo)
|
||||
router.post('/users', async (req, res) => {
|
||||
try {
|
||||
const { name, email, password, role, dept } = req.body;
|
||||
if (!name || !email || !password) {
|
||||
return res.status(400).json({ error: 'Name, email and password required' });
|
||||
}
|
||||
|
||||
const [existing] = await pool.query('SELECT id FROM users WHERE email = ?', [email]);
|
||||
if (existing.length > 0) {
|
||||
return res.status(409).json({ error: 'Email already registered' });
|
||||
}
|
||||
|
||||
const id = randomUUID();
|
||||
const password_hash = await bcrypt.hash(password, 10);
|
||||
const avatar = name.split(' ').map(w => w[0]).join('').substring(0, 2).toUpperCase();
|
||||
const colors = ['#818cf8', '#f59e0b', '#34d399', '#f472b6', '#fb923c', '#60a5fa', '#a78bfa'];
|
||||
const color = colors[Math.floor(Math.random() * colors.length)];
|
||||
|
||||
await pool.query(
|
||||
'INSERT INTO users (id, name, role, email, password_hash, color, avatar, dept) VALUES (?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
[id, name, role || 'employee', email, password_hash, color, avatar, dept || '']
|
||||
);
|
||||
|
||||
res.status(201).json({ id, name, role: role || 'employee', email, color, avatar, dept: dept || '' });
|
||||
} catch (err) {
|
||||
console.error('Create user error:', err);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// DELETE /api/auth/users/:id — Delete a user (unassign their tasks first)
|
||||
router.delete('/users/:id', async (req, res) => {
|
||||
try {
|
||||
const { id } = req.params;
|
||||
|
||||
const [user] = await pool.query('SELECT id FROM users WHERE id = ?', [id]);
|
||||
if (user.length === 0) {
|
||||
return res.status(404).json({ error: 'User not found' });
|
||||
}
|
||||
|
||||
// Unassign tasks assigned to or reported by this user
|
||||
await pool.query('UPDATE tasks SET assignee_id = NULL WHERE assignee_id = ?', [id]);
|
||||
await pool.query('UPDATE tasks SET reporter_id = NULL WHERE reporter_id = ?', [id]);
|
||||
|
||||
// Delete the user (cascading will handle comments, etc. via ON DELETE SET NULL)
|
||||
await pool.query('DELETE FROM users WHERE id = ?', [id]);
|
||||
|
||||
res.json({ success: true, id });
|
||||
} catch (err) {
|
||||
console.error('Delete user error:', err);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
|
||||
Reference in New Issue
Block a user