From cd0aeff7dd0ac61f5fac466c0f0f91304b364fad Mon Sep 17 00:00:00 2001 From: Nicolas Date: Mon, 30 Dec 2024 16:30:23 +0100 Subject: [PATCH] users --- backend/src/controllers/user.ts | 12 ++++++++---- frontend/src/actions/userActions.ts | 19 +++++++++++++++++++ frontend/src/components/client/EditClient.tsx | 5 ++++- .../src/components/project/EditProject.tsx | 2 +- .../src/components/socketio/SocketService.ts | 2 ++ frontend/src/components/users/EditUser.tsx | 6 +++++- frontend/src/trans.nl.ts | 3 ++- 7 files changed, 41 insertions(+), 8 deletions(-) diff --git a/backend/src/controllers/user.ts b/backend/src/controllers/user.ts index 00883e8c..78d7c250 100644 --- a/backend/src/controllers/user.ts +++ b/backend/src/controllers/user.ts @@ -3,11 +3,12 @@ import {Request, Response} from 'express'; import {ObjectID} from 'mongodb'; import {OAuth2Client, TokenPayload} from 'google-auth-library'; import jwt from 'jsonwebtoken'; -import {CollectionNames, IAudit, createAudit, updateAudit} from '../models/common'; +import {CollectionNames, IAudit, SocketEventTypes, createAudit, updateAudit} from '../models/common'; import config from '../config'; import {IUser, IRole} from '../models/user'; import {ConfacRequest} from '../models/technical'; import {saveAudit} from './utils/audit-logs'; +import { emitEntityEvent } from './utils/entity-events'; const AdminRole = 'admin'; @@ -111,13 +112,16 @@ export const saveUser = async (req: ConfacRequest, res: Response) => { user.audit = updateAudit(user.audit, req.user); const {value: originalUser} = await collection.findOneAndUpdate({_id: new ObjectID(_id)}, {$set: user}, {returnOriginal: true}); await saveAudit(req, 'user', originalUser, user); - return res.send({_id, ...user}); + const responseUser = {_id, ...user}; + emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.USERS, _id, responseUser); + return res.send(responseUser); } user.audit = createAudit(req.user); const inserted = await collection.insertOne(user); - const [createdClient] = inserted.ops; - return res.send(createdClient); + const [createdUser] = inserted.ops; + emitEntityEvent(req, SocketEventTypes.EntityCreated, CollectionNames.USERS, createdUser._id, createdUser); + return res.send(createdUser); }; diff --git a/frontend/src/actions/userActions.ts b/frontend/src/actions/userActions.ts index 1d85b78d..8c2f2591 100644 --- a/frontend/src/actions/userActions.ts +++ b/frontend/src/actions/userActions.ts @@ -7,6 +7,9 @@ import {catchHandler} from './utils/fetch'; import {busyToggle, success} from './appActions'; import {ACTION_TYPES} from './utils/ActionTypes'; import { socketService } from '../components/socketio/SocketService'; +import { SocketEventTypes } from '../components/socketio/SocketEventTypes'; +import { Dispatch } from 'redux'; +import { EntityEventPayload } from '../components/socketio/EntityEventPayload'; export function saveUser(user: UserModel, callback?: (savedUser: UserModel) => void, navigate?: any) { @@ -36,6 +39,22 @@ export function saveUser(user: UserModel, callback?: (savedUser: UserModel) => v }; } +export function handleUserSocketEvents(eventType: string, eventPayload: EntityEventPayload){ + return (dispatch: Dispatch) => { + dispatch(busyToggle()); + switch(eventType){ + case SocketEventTypes.EntityUpdated: + case SocketEventTypes.EntityCreated: + dispatch({ + type: ACTION_TYPES.USER_UPDATE, + user: eventPayload.entity, + }); break; + default: throw new Error(`${eventType} not supported for user.`); + } + dispatch(busyToggle.off()); + } +} + export function saveRole(role: RoleModel, callback?: (savedRole: RoleModel) => void, navigate?: any) { return dispatch => { diff --git a/frontend/src/components/client/EditClient.tsx b/frontend/src/components/client/EditClient.tsx index 5f36fa39..5b64d001 100644 --- a/frontend/src/components/client/EditClient.tsx +++ b/frontend/src/components/client/EditClient.tsx @@ -40,10 +40,13 @@ const EditClient = () => { const initClient = getClient(storeClient, config); const [client, setClient] = useState(initClient); const clientWithSameKbo = useSelector((state: ConfacState) => state.clients.filter(x => x.btw === client.btw).find(x => x.slug !== params.id)); + + useEntityChangedToast(client._id); + const dispatch = useDispatch(); // useEffect(() => window.scrollTo(0, 0)); // TODO: each keystroke made it scroll to top :( useDocumentTitle('clientEdit', {name: client.name}); - useEntityChangedToast(client._id); + if (storeClient && !client._id) { setClient(storeClient); diff --git a/frontend/src/components/project/EditProject.tsx b/frontend/src/components/project/EditProject.tsx index 3cbe73d1..7726b41d 100644 --- a/frontend/src/components/project/EditProject.tsx +++ b/frontend/src/components/project/EditProject.tsx @@ -43,7 +43,7 @@ export const EditProject = () => { const client = useSelector((state: ConfacState) => state.clients.find(x => x._id === project.client.clientId) || getNewClient()); const hasProjectMonths = useSelector((state: ConfacState) => state.projectsMonth.some(pm => pm.projectId === params.id)); const [needsSync, setNeedsSync] = useState<{consultant: boolean, client: boolean}>({consultant: false, client: false}); - + useEntityChangedToast(model?._id); const docTitle = consultant._id ? 'projectEdit' : 'projectNew'; diff --git a/frontend/src/components/socketio/SocketService.ts b/frontend/src/components/socketio/SocketService.ts index 2c827313..5ffc2d79 100644 --- a/frontend/src/components/socketio/SocketService.ts +++ b/frontend/src/components/socketio/SocketService.ts @@ -6,6 +6,7 @@ import { SocketEventTypes } from "./SocketEventTypes"; import { EntityEventPayload } from "./EntityEventPayload"; import { t } from "../utils"; import { toast } from "react-toastify"; +import { handleUserSocketEvents } from "../../actions/userActions"; function createSocketService () { // TODO nicolas read server url from frontend config !!! @@ -41,6 +42,7 @@ function createSocketService () { case 'projects': dispatch(handleProjectSocketEvents(eventType, eventPayload)); break; case 'consultants': dispatch(handleConsultantSocketEvents(eventType, eventPayload)); break; case 'clients': dispatch(handleClientSocketEvents(eventType, eventPayload)); break; + case 'users': dispatch(handleUserSocketEvents(eventType, eventPayload)); break; default: throw new Error(`${eventPayload.entityType} event for entity type not supported.`); }; }); diff --git a/frontend/src/components/users/EditUser.tsx b/frontend/src/components/users/EditUser.tsx index 962ed6bd..5e5d24c5 100644 --- a/frontend/src/components/users/EditUser.tsx +++ b/frontend/src/components/users/EditUser.tsx @@ -14,6 +14,7 @@ import {useDocumentTitle} from '../hooks/useDocumentTitle'; import {saveUser} from '../../actions/userActions'; import {Audit} from '../admin/audit/Audit'; import {useParams} from 'react-router-dom'; +import useEntityChangedToast from '../hooks/useEntityChangedToast'; @@ -23,9 +24,12 @@ export const EditUser = () => { const params = useParams(); const model = useSelector((state: ConfacState) => state.user.users.find(c => c.alias === params.id)); const [user, setUser] = useState(model || getNewUser()); - + + useEntityChangedToast(user._id); + const docTitle = user._id ? 'userEdit' : 'userNew'; useDocumentTitle(docTitle, {name: `${user.firstName} ${user.name}`}); + if (model && !user._id) { setUser(model); diff --git a/frontend/src/trans.nl.ts b/frontend/src/trans.nl.ts index 167cd099..091ec01e 100644 --- a/frontend/src/trans.nl.ts +++ b/frontend/src/trans.nl.ts @@ -681,7 +681,8 @@ export const trans = { entities: { projects: 'Project', consultants: 'Consultant', - clients: 'Klant' + clients: 'Klant', + users: 'Gebruiker' }, operation: { entityUpdated: '{entityType} werd aangepast door {user}',