Skip to content

Commit

Permalink
project month wip
Browse files Browse the repository at this point in the history
  • Loading branch information
NicolasHub committed Dec 30, 2024
1 parent fc98fde commit 1155cee
Show file tree
Hide file tree
Showing 11 changed files with 66 additions and 18 deletions.
12 changes: 9 additions & 3 deletions backend/src/controllers/projectsMonth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import {Request, Response} from 'express';
import {ObjectID} from 'mongodb';
import moment from 'moment';
import {IProjectMonth, IProjectMonthOverview, TimesheetCheckAttachmentType} from '../models/projectsMonth';
import {CollectionNames, createAudit, updateAudit} from '../models/common';
import {CollectionNames, createAudit, SocketEventTypes, updateAudit} from '../models/common';
import {ConfacRequest} from '../models/technical';
import {saveAudit} from './utils/audit-logs';
import { emitEntityEvent } from './utils/entity-events';


export const getProjectsPerMonthController = async (req: Request, res: Response) => {
Expand Down Expand Up @@ -55,6 +56,8 @@ export const createProjectsMonthController = async (req: ConfacRequest, res: Res
return createdProjectMonth;
}));

emitEntityEvent(req, SocketEventTypes.EntityCreated, CollectionNames.PROJECTS_MONTH, null, createdProjectsMonth);

return res.send(createdProjectsMonth);
};

Expand All @@ -68,15 +71,17 @@ export const patchProjectsMonthController = async (req: ConfacRequest, res: Resp
const projMonthCollection = req.db.collection<IProjectMonth>(CollectionNames.PROJECTS_MONTH);
const {value: originalProjectMonth} = await projMonthCollection.findOneAndUpdate({_id: new ObjectID(_id)}, {$set: projectMonth}, {returnOriginal: true});
await saveAudit(req, 'projectMonth', originalProjectMonth, projectMonth);
return res.send({_id, ...projectMonth});
const projectMonthResponse = {_id, ...projectMonth};
emitEntityEvent(req, SocketEventTypes.EntityUpdated, CollectionNames.PROJECTS_MONTH, projectMonthResponse._id, projectMonthResponse);
return res.send(projectMonthResponse);
}

const inserted = await req.db.collection<IProjectMonth>(CollectionNames.PROJECTS_MONTH).insertOne({
...projectMonth,
audit: createAudit(req.user),
});
const [createdProjectMonth] = inserted.ops;

emitEntityEvent(req, SocketEventTypes.EntityCreated, CollectionNames.PROJECTS_MONTH, createdProjectMonth._id, createdProjectMonth);
return res.send(createdProjectMonth);
};

Expand All @@ -86,5 +91,6 @@ export const deleteProjectsMonthController = async (req: ConfacRequest, res: Res
const id = req.body.id;
await req.db.collection(CollectionNames.PROJECTS_MONTH).findOneAndDelete({ _id: new ObjectID(id) });
await req.db.collection(CollectionNames.ATTACHMENTS_PROJECT_MONTH).findOneAndDelete({ _id: new ObjectID(id) });
emitEntityEvent(req, SocketEventTypes.EntityDeleted, CollectionNames.PROJECTS_MONTH, id, null);
return res.send(id);
};
4 changes: 2 additions & 2 deletions backend/src/controllers/utils/entity-events.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { ObjectID } from 'bson';
import {CollectionNames, SocketEventTypes} from '../../models/common';
import {ConfacRequest} from '../../models/technical';

export function emitEntityEvent(req: ConfacRequest, eventType: SocketEventTypes, entityType: CollectionNames, entityId: ObjectID, entity:any) {
export function emitEntityEvent(req: ConfacRequest, eventType: SocketEventTypes, entityType: CollectionNames, entityId: ObjectID | null, entity: any|null) {
const sourceSocketId = req.headers['x-socket-id'];
const sourceUserEmail = req.user?.data?.email;
req.io.emit(eventType, {
Expand All @@ -17,7 +17,7 @@ export function emitEntityEvent(req: ConfacRequest, eventType: SocketEventTypes,
interface EntityEventPayload{
entityType: string;
entity: any;
entityId: ObjectID;
entityId: ObjectID | null;
sourceSocketId: string | undefined;
sourceUserEmail: string | undefined;
}
4 changes: 2 additions & 2 deletions backend/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ const server = http.createServer(app);
const io = new Server(server, {
cors: {
origin: '*', // Allow all origins
methods: ['GET', 'POST'], // Allowed HTTP methods
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], // Allowed HTTP methods
allowedHeaders: ['x-socket-id'], // Optional: specify allowed headers
credentials: true, // Allow credentials (e.g., cookies)
},
Expand All @@ -31,7 +31,7 @@ sgMail.setApiKey(appConfig.SENDGRID_API_KEY);
// Allow only specific origins (e.g., your frontend's URL)
const corsOptions = {
origin: 'http://localhost:3000', // Replace with your frontend URL
methods: ['GET', 'POST', 'PUT', 'DELETE'], // Allowed HTTP methods
methods: ['GET', 'POST', 'PUT', 'DELETE', 'PATCH'], // Allowed HTTP methods
allowedHeaders: ['Content-Type', 'Authorization', 'x-socket-id'], // Allowed headers
credentials: true, // Allow cookies and credentials
};
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/actions/configActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export function updateConfig(newConfig: ConfigModel) {
};
}

export function handleconfigSocketEvents(eventType: string, eventPayload: EntityEventPayload){
export function handleConfigSocketEvents(eventType: string, eventPayload: EntityEventPayload){
return (dispatch: Dispatch) => {
dispatch(busyToggle());
switch(eventType){
Expand Down
29 changes: 29 additions & 0 deletions frontend/src/actions/projectActions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -263,4 +263,33 @@ export function handleProjectSocketEvents(eventType: string, eventPayload: Entit
}
dispatch(busyToggle.off());
}
}

export function handleProjectMonthSocketEvents(eventType: string, eventPayload: EntityEventPayload){
return (dispatch: Dispatch) => {
dispatch(busyToggle());
switch(eventType){
case SocketEventTypes.EntityUpdated:
case SocketEventTypes.EntityCreated:
if(Array.isArray(eventPayload.entity)){
dispatch({
type: ACTION_TYPES.PROJECTS_MONTH_FETCHED,
projectsMonth: eventPayload.entity,
});
}else{
dispatch({
type: ACTION_TYPES.PROJECTS_MONTH_UPDATE,
projectMonth: eventPayload.entity,
});
}
break;
case SocketEventTypes.EntityDeleted:
dispatch({
type: ACTION_TYPES.PROJECTS_MONTH_DELETE,
id: eventPayload.entityId,
}); break;
default: throw new Error(`${eventType} not supported for project month.`);
}
dispatch(busyToggle.off());
}
}
8 changes: 4 additions & 4 deletions frontend/src/components/hooks/useEntityChangedToast.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
import { useEffect } from "react";
import { socketService } from "../socketio/SocketService";

function useEntityChangedToast(entityId: string|null|undefined) {
function useEntityChangedToast(entityId: string|null|undefined, entityType: string|null|undefined = null) {
useEffect(()=>{
var subs: undefined| (()=>void);

if(entityId){
subs = socketService.enableToastsForEntity(entityId);
if(entityId || entityType ){
subs = socketService.enableToastsForEntity(entityId, entityType);
}

return subs;

}, [entityId]);
}, [entityId, entityType]);
}

export default useEntityChangedToast;
3 changes: 3 additions & 0 deletions frontend/src/components/project/EditProjectMonths.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {useProjectsMonth} from '../hooks/useProjects';
import {EnhanceWithConfirmation} from '../enhancers/EnhanceWithConfirmation';
import {Button} from '../controls/form-controls/Button';
import {useParams} from 'react-router-dom';
import useEntityChangedToast from '../hooks/useEntityChangedToast';

const ConfirmationButton = EnhanceWithConfirmation(Button);

Expand All @@ -27,6 +28,8 @@ export const EditProjectMonths = () => {
const model = useProjectsMonth(params.projectMonthId);
const [projectMonth, setProjectMonth] = useState<ProjectMonthModel>((model && model.details) || getNewProjectMonth());

useEntityChangedToast(model?._id);

const docTitle = projectMonth._id ? 'projectMonthEdit' : 'projectMonthNew';
const consultantName = (model && model.consultantName) || '';
const clientName = (model && model.client.name) || '';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { ProjectMonthsListToolbar } from './ProjectMonthsListToolbar';


import './project-month-list.scss';
import useEntityChangedToast from '../../hooks/useEntityChangedToast';


/** The monthly invoicing tables including the top searchbar */
Expand All @@ -21,6 +22,8 @@ export const ProjectMonthsLists = () => {
.filter((month, index, arr) => arr.indexOf(month) === index)
.sort((a, b) => b.localeCompare(a));

useEntityChangedToast(null, 'projects_month');

return (
<Container className={`list list-${Features.projectMonths}`}>
<ProjectMonthsListToolbar />
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/socketio/EntityEventPayload.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export interface EntityEventPayload {
entityType: string;
entity: any;
entityId: string;
entityId: string | null;
sourceSocketId: string | undefined;
sourceUserEmail: string | undefined;
}
14 changes: 10 additions & 4 deletions frontend/src/components/socketio/SocketService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

import { Dispatch } from "redux";
import { io } from "socket.io-client";
import { handleClientSocketEvents, handleconfigSocketEvents, handleConsultantSocketEvents, handleProjectSocketEvents } from "../../actions";
import { handleClientSocketEvents, handleConfigSocketEvents, handleConsultantSocketEvents, handleProjectMonthSocketEvents, handleProjectSocketEvents } from "../../actions";
import { SocketEventTypes } from "./SocketEventTypes";
import { EntityEventPayload } from "./EntityEventPayload";
import { t } from "../utils";
Expand Down Expand Up @@ -44,7 +44,8 @@ function createSocketService () {
case 'clients': dispatch(handleClientSocketEvents(eventType, eventPayload)); break;
case 'users': dispatch(handleUserSocketEvents(eventType, eventPayload)); break;
case 'roles': dispatch(handleRoleSocketEvents(eventType, eventPayload)); break;
case 'config': dispatch(handleconfigSocketEvents(eventType, eventPayload)); break;
case 'config': dispatch(handleConfigSocketEvents(eventType, eventPayload)); break;
case 'projects_month': dispatch(handleProjectMonthSocketEvents(eventType, eventPayload)); break;
default: throw new Error(`${eventPayload.entityType} event for entity type not supported.`);
};
});
Expand All @@ -70,6 +71,7 @@ function createSocketService () {
default: throw new Error(`${eventType} not supported.`);
}

// TODO nicolas debounce toasts
toast.info(
t(`socketio.operation.${operation}`, {
entityType: t(`socketio.entities.${eventPayload.entityType}`),
Expand All @@ -79,7 +81,7 @@ function createSocketService () {
);
}

function enableToastsForEntity(entityId: string) {
function enableToastsForEntity(entityId: string|null|undefined, entityType: string|null|undefined) {
var unsubscriptions: (()=>void)[] = [];

function registerHandlerForEventType(eventType: SocketEventTypes){
Expand All @@ -89,10 +91,14 @@ function createSocketService () {
console.log("Event ignored for entityId subscription => source socket id is self");
return;
}
if(msg.entityId !== entityId){
if(!!entityId && msg.entityId !== entityId){
console.log("Event ignored for entityId subscription => entity id not match");
return;
}
if(!!entityType && msg.entityType !== entityType){
console.log("Event ignored for entityType subscription => entity type not match");
return;
}
toastEntityChanged(eventType, msg);
};

Expand Down
3 changes: 2 additions & 1 deletion frontend/src/trans.nl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -684,7 +684,8 @@ export const trans = {
clients: 'Klant',
users: 'Gebruiker',
roles: 'Rol',
config: 'Configuratie'
config: 'Configuratie',
projects_month: 'Project maand'
},
operation: {
entityUpdated: '{entityType} werd aangepast door {user}',
Expand Down

0 comments on commit 1155cee

Please sign in to comment.