websocket updates

* sync page title on icon via websocket
* sync on page tree too
This commit is contained in:
Philipinho
2024-04-27 15:40:22 +01:00
parent 390d58793a
commit 8cc7d39146
17 changed files with 253 additions and 15 deletions

View File

@ -0,0 +1,4 @@
import { atom } from "jotai";
import { Socket } from "socket.io-client";
export const socketAtom = atom<Socket | null>(null);

View File

@ -0,0 +1,3 @@
export const SOCKET_URL = import.meta.env.DEV
? "http://localhost:3000"
: undefined;

View File

@ -0,0 +1,2 @@
export * from "./types.ts";
export * from "./constants.ts";

View File

@ -0,0 +1,14 @@
export type InvalidateEvent = {
operation: "invalidate";
entity: Array<string>;
id?: string;
};
export type UpdateEvent = {
operation: "updateOne";
entity: Array<string>;
id: string;
payload: Partial<any>;
};
export type WebSocketEvent = InvalidateEvent | UpdateEvent;

View File

@ -0,0 +1,11 @@
import { socketAtom } from "@/features/websocket/atoms/socket-atom.ts";
import { useAtom } from "jotai";
import { WebSocketEvent } from "@/features/websocket/types";
export const useQueryEmit = () => {
const [socket] = useAtom(socketAtom);
return (input: WebSocketEvent) => {
socket?.emit("message", input);
};
};

View File

@ -0,0 +1,43 @@
import React from "react";
import { socketAtom } from "@/features/websocket/atoms/socket-atom.ts";
import { useAtom } from "jotai";
import { useQueryClient } from "@tanstack/react-query";
import { WebSocketEvent } from "@/features/websocket/types";
export const useQuerySubscription = () => {
const queryClient = useQueryClient();
const [socket] = useAtom(socketAtom);
React.useEffect(() => {
socket?.on("message", (event) => {
const data: WebSocketEvent = event;
switch (data.operation) {
case "invalidate":
queryClient.invalidateQueries({
queryKey: [...data.entity, data.id].filter(Boolean),
});
break;
case "updateOne":
queryClient.setQueryData([...data.entity, data.id], {
...queryClient.getQueryData([...data.entity, data.id]),
...data.payload,
});
/*
queryClient.setQueriesData(
{ queryKey: [data.entity, data.id] },
(oldData: any) => {
const update = (entity: Record<string, unknown>) =>
entity.id === data.id ? { ...entity, ...data.payload } : entity;
return Array.isArray(oldData)
? oldData.map(update)
: update(oldData as Record<string, unknown>);
},
);
*/
break;
}
});
}, [queryClient, socket]);
};

View File

@ -0,0 +1,62 @@
import { useEffect, useRef } from "react";
import { socketAtom } from "@/features/websocket/atoms/socket-atom.ts";
import { useAtom } from "jotai";
import { treeDataAtom } from "@/features/page/tree/atoms/tree-data-atom.ts";
import {
updateTreeNodeIcon,
updateTreeNodeName,
} from "@/features/page/tree/utils";
import { WebSocketEvent } from "@/features/websocket/types";
import { SpaceTreeNode } from "@/features/page/tree/types.ts";
export const useTreeSocket = () => {
const [socket] = useAtom(socketAtom);
const [treeData, setTreeData] = useAtom(treeDataAtom);
const initialTreeData = useRef(treeData);
useEffect(() => {
initialTreeData.current = treeData;
}, [treeData]);
useEffect(() => {
socket?.on("message", (event) => {
const data: WebSocketEvent = event;
const initialData = initialTreeData.current;
switch (data.operation) {
case "invalidate":
// nothing to do here
break;
case "updateOne":
// Get the initial value of treeData
if (initialData && initialData.length > 0) {
let newTreeData: SpaceTreeNode[];
if (data.entity[0] === "pages") {
if (data.payload?.title !== undefined) {
newTreeData = updateTreeNodeName(
initialData,
data.id,
data.payload.title,
);
}
if (data.payload?.icon !== undefined) {
newTreeData = updateTreeNodeIcon(
initialData,
data.id,
data.payload.icon,
);
}
if (newTreeData && newTreeData.length > 0) {
setTreeData(newTreeData);
}
}
}
break;
}
});
}, [socket]);
};