87 lines
2.2 KiB
TypeScript
87 lines
2.2 KiB
TypeScript
|
import * as Automerge from "@automerge/automerge";
|
||
|
import { useContext, useState } from "react";
|
||
|
import useWebSocket from "react-use-websocket";
|
||
|
import { wsUrl } from "./constants";
|
||
|
import CBOR from "cbor";
|
||
|
import { RoomContext } from "./lib/roomContext";
|
||
|
|
||
|
export default function Grub() {
|
||
|
const { roomId, clientId } = useContext(RoomContext);
|
||
|
const [doc, setDoc] = useState(Automerge.init());
|
||
|
const [syncState, setSyncState] = useState(Automerge.initSyncState());
|
||
|
const [addItemName, setAddItemName] = useState("");
|
||
|
|
||
|
function updateDoc(newDoc) {
|
||
|
setDoc(newDoc);
|
||
|
}
|
||
|
|
||
|
const { sendMessage } = useWebSocket(wsUrl, {
|
||
|
share: true,
|
||
|
onOpen: ({}) => {
|
||
|
console.log("Shiet, connected.");
|
||
|
},
|
||
|
onMessage: async (event) => {
|
||
|
const data = CBOR.decode(await event.data.arrayBuffer());
|
||
|
|
||
|
if (data.type === "Automerge") {
|
||
|
const [nextDoc, nextSyncState, patch] = Automerge.receiveSyncMessage(
|
||
|
doc,
|
||
|
syncState,
|
||
|
data.message[1]
|
||
|
);
|
||
|
setDoc(nextDoc);
|
||
|
setSyncState(nextSyncState);
|
||
|
console.log("patch", patch);
|
||
|
}
|
||
|
},
|
||
|
});
|
||
|
|
||
|
function sendCborMessage(data) {
|
||
|
let cbor = CBOR.encode(data);
|
||
|
sendMessage(cbor);
|
||
|
}
|
||
|
|
||
|
function addItem(e) {
|
||
|
e.preventDefault();
|
||
|
const newDoc = Automerge.change(doc, (doc) => {
|
||
|
if (!doc.items) doc.items = [];
|
||
|
doc.items.push({
|
||
|
id: uuid.v4(),
|
||
|
content: addItemName,
|
||
|
});
|
||
|
});
|
||
|
updateDoc(newDoc);
|
||
|
const [syncMessage, binary] = Automerge.generateSyncMessage(doc, syncState);
|
||
|
if (syncMessage)
|
||
|
sendCborMessage({
|
||
|
type: "Automerge",
|
||
|
client_id: clientId,
|
||
|
room_id: roomId,
|
||
|
message: binary,
|
||
|
});
|
||
|
setAddItemName("");
|
||
|
}
|
||
|
|
||
|
const items = doc.items || [];
|
||
|
|
||
|
return (
|
||
|
<>
|
||
|
Grubs:
|
||
|
<ul>
|
||
|
{items.map((x) => (
|
||
|
<li key={x.id}>{x.content}</li>
|
||
|
))}
|
||
|
</ul>
|
||
|
<form onSubmit={addItem}>
|
||
|
<input
|
||
|
type="text"
|
||
|
value={addItemName}
|
||
|
onChange={(e) => setAddItemName(e.target.value)}
|
||
|
placeholder="Type a message..."
|
||
|
/>
|
||
|
<button type="submit">add item</button>
|
||
|
</form>
|
||
|
</>
|
||
|
);
|
||
|
}
|