Skip to content

Commit

Permalink
Refactor people socket setup and initialization
Browse files Browse the repository at this point in the history
- Core socket setup is found inside the local socketSetup function
- This is exposed via another setupSocket on the store Actions interface
- The project subscription is managed by the People.tsx component (the
page)
  • Loading branch information
tomtitherington committed Nov 20, 2023
1 parent 58eff51 commit a641bb6
Show file tree
Hide file tree
Showing 3 changed files with 137 additions and 152 deletions.
78 changes: 0 additions & 78 deletions frontend/src/features/people/hooks/usePeopleSocket.ts

This file was deleted.

31 changes: 23 additions & 8 deletions frontend/src/features/people/pages/People.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,37 @@ import { SegmentSelector, SelectedRowsBar, Table } from '../components';
import { MdAdd, MdConstruction } from 'react-icons/md';
import { usePeopleStore } from '../stores/usePeopleStore';
import { SoonLabel } from 'components';
import { usePeopleSocket } from '../hooks/usePeopleSocket';
import { useEffect, useRef } from 'react';
import { useProjectsStore } from 'features/projects/stores/useProjectsStore';
import { isHasData } from 'api/utils';

const People = () => {
const selectedProject = useProjectsStore(state => state.selectedProject);
const isActive = isHasData(selectedProject) && !!selectedProject.data.api_key;
const socketUrl = isActive
? `ws://localhost:8001/ws/people/?api_key=${selectedProject.data.api_key}`
: '';
usePeopleSocket({ url: socketUrl, isActive });

const addRow = usePeopleStore(state => state.addRow);
const selectedRowCount = usePeopleStore(
state => Object.values(state.rowSelection || {}).filter(value => value).length,
);

const destroy = usePeopleStore(state => state.destroy);
const setupSocket = usePeopleStore(state => state.setupSocket);
useEffect(() => {
// We track changes to the select project as we need the api_key in our socket connection
const unsubscribe = useProjectsStore.subscribe(
state => state.selectedProject,
(selectedProjectState, prevSelectedProjectState) => {
if (isHasData(selectedProjectState) && !!selectedProjectState.data.api_key) {
const socketUrl = `ws://localhost:8001/ws/people/?api_key=${selectedProjectState.data.api_key}`;
setupSocket(socketUrl);
}
},
{ fireImmediately: true },
);

return () => {
destroy();
unsubscribe();
};
}, [destroy, setupSocket]);

return (
<div className="h-full w-full flex flex-row">
<div className="flex-none w-64 self-stretch flex flex-col p-4 py-8 gap-4 border-r border-crumpet-light-300">
Expand Down
180 changes: 114 additions & 66 deletions frontend/src/features/people/stores/usePeopleStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,73 +25,121 @@ interface Actions {
addRow: () => void;
setRowSelection: (newRowSelection: RowSelectionState) => void;
deleteSelectedRows: () => void;
setupSocket: (url: string) => void;
destroy: () => void;
}

export const usePeopleStore = create<State & Actions>()(
subscribeWithSelector(set => ({
data: [
{ name: 'Jane Doe', age: 30 },
{ name: 'Jane Doe', age: 32 },
{ name: 'Earl Grey of West Sussex', age: 400000000 },
// ... more data
],
updateData: (rowIndex: number, columnId: string, value: unknown) =>
set(
produce<State>(draft => {
const row = draft.data[rowIndex] as Record<string, any>;
if (row) {
row[columnId] = value;
}
}),
),
addRow: () =>
set(
produce<State>(draft => {
draft.data.push({});
}),
),
rowSelection: {},
propertyDefinitions: {
id_1: { accessor: 'name', header: 'Name' },
id_2: { accessor: 'age', header: 'Age' },
},
upsertDefinition: (id, newDefinition) =>
set(
produce<State>(draft => {
if (draft.propertyDefinitions[id]) {
// If the definition exists, merge it
Object.assign(draft.propertyDefinitions[id], newDefinition);
} else {
// If the definition does not exist, create a new one
// (you should validate the full object structure here)
draft.propertyDefinitions[id] = newDefinition as Omit<PropertyDefinition, 'id'>;
}
}),
),
deleteDefinition: (
id, // Implement the delete function
) =>
set(
produce<State>(draft => {
delete draft.propertyDefinitions[id];
}),
),
setRowSelection: newRowSelection =>
set(
produce<State>(draft => {
draft.rowSelection = newRowSelection;
}),
),
deleteSelectedRows: () =>
set(
produce<State>(draft => {
if (draft.rowSelection) {
// Filter out the rows that are selected
draft.data = draft.data.filter((_, index) => !draft.rowSelection?.[index]);
// Reset the rowSelection state after deletion
draft.rowSelection = {};
}
}),
),
})),
subscribeWithSelector((set, get) => {
return {
setupSocket: url => {
setupSocket(set, url);
},
destroy: () => {
if (socket) {
socket.close();
}
},
data: [
{ name: 'Jane Doe', age: 30 },
{ name: 'Jane Doe', age: 32 },
{ name: 'Earl Grey of West Sussex', age: 400000000 },
// ... more data
],
updateData: (rowIndex: number, columnId: string, value: unknown) => {
// Update store
set(
produce<State>(draft => {
const row = draft.data[rowIndex] as Record<string, any>;
if (row) {
row[columnId] = value;
}
}),
);
// Send message over socket
socket?.send(JSON.stringify({ message: 'testing' }));
},
addRow: () =>
set(
produce<State>(draft => {
draft.data.push({});
}),
),
rowSelection: {},
propertyDefinitions: {
id_1: { accessor: 'name', header: 'Name' },
id_2: { accessor: 'age', header: 'Age' },
},
upsertDefinition: (id, newDefinition) =>
set(
produce<State>(draft => {
if (draft.propertyDefinitions[id]) {
// If the definition exists, merge it
Object.assign(draft.propertyDefinitions[id], newDefinition);
} else {
// If the definition does not exist, create a new one
// (you should validate the full object structure here)
draft.propertyDefinitions[id] = newDefinition as Omit<PropertyDefinition, 'id'>;
}
}),
),
deleteDefinition: (
id, // Implement the delete function
) =>
set(
produce<State>(draft => {
delete draft.propertyDefinitions[id];
}),
),
setRowSelection: newRowSelection =>
set(
produce<State>(draft => {
draft.rowSelection = newRowSelection;
}),
),
deleteSelectedRows: () =>
set(
produce<State>(draft => {
if (draft.rowSelection) {
// Filter out the rows that are selected
draft.data = draft.data.filter((_, index) => !draft.rowSelection?.[index]);
// Reset the rowSelection state after deletion
draft.rowSelection = {};
}
}),
),
};
}),
);

let socket: WebSocket | null = null;

const setupSocket = (set: any, url?: string | null) => {
if (socket) {
console.log('closing inside initializeSocket');
socket.close();
}
if (url == null) return;

console.log('settings up socket');

socket = new WebSocket(url);

socket.onopen = () => {
/* handle open */
if (socket == null) return;
console.log('Sending message');
socket.send(JSON.stringify({ message: 'testing' }));
};
socket.onmessage = e => {
/* handle incoming messages */
const wsData = JSON.parse(e.data);
console.log(wsData);
};
socket.onerror = error => {
/* handle error */
};
socket.onclose = () => {
/* handle close */
};
};

0 comments on commit a641bb6

Please sign in to comment.