2021-01-16 12:28:01 +03:00
|
|
|
import _ from 'lodash';
|
|
|
|
import { useEffect, useState } from 'react';
|
|
|
|
import { subscribeToEvent } from '@fluencelabs/fluence';
|
|
|
|
|
2021-01-16 13:24:26 +03:00
|
|
|
import { fluentPadServiceId, notifyTextUpdateFnName } from 'src/app/constants';
|
|
|
|
import { useFluenceClient } from '../app/FluenceClientContext';
|
|
|
|
import { getUpdatedDocFromText, initDoc, SyncClient } from '../app/sync';
|
|
|
|
import * as calls from 'src/app/api';
|
2021-01-14 13:17:48 +03:00
|
|
|
|
2021-01-16 12:28:01 +03:00
|
|
|
const broadcastUpdates = _.debounce((text: string, syncClient: SyncClient) => {
|
|
|
|
let doc = syncClient.getDoc();
|
|
|
|
if (doc) {
|
|
|
|
let newDoc = getUpdatedDocFromText(doc, text);
|
|
|
|
syncClient.syncDoc(newDoc);
|
2021-01-14 23:57:24 +03:00
|
|
|
}
|
2021-01-16 12:28:01 +03:00
|
|
|
}, 100);
|
2021-01-16 00:48:57 +03:00
|
|
|
|
2021-01-14 13:17:48 +03:00
|
|
|
export const CollaborativeEditor = () => {
|
|
|
|
const client = useFluenceClient()!;
|
2021-01-16 01:38:09 +03:00
|
|
|
const [text, setText] = useState('');
|
2021-01-16 12:28:01 +03:00
|
|
|
const [syncClient, setSyncClient] = useState(new SyncClient());
|
2021-01-14 13:17:48 +03:00
|
|
|
|
|
|
|
useEffect(() => {
|
2021-01-16 12:28:01 +03:00
|
|
|
syncClient.syncDoc(initDoc());
|
|
|
|
syncClient.handleDocUpdate = (doc) => {
|
|
|
|
console.log('syncClient.handleDocUpdate');
|
|
|
|
setText(doc.text.toString());
|
|
|
|
};
|
|
|
|
|
|
|
|
syncClient.handleSendChanges = (changes: string) => {
|
|
|
|
console.log('syncClient.handleSendChanges');
|
|
|
|
calls.addEntry(client, changes);
|
|
|
|
};
|
2021-01-16 01:38:09 +03:00
|
|
|
|
2021-01-16 12:28:01 +03:00
|
|
|
const unsub = subscribeToEvent(client, fluentPadServiceId, notifyTextUpdateFnName, (args, tetraplets) => {
|
|
|
|
const [authorPeerId, changes, isAuthorized] = args;
|
2021-01-16 00:48:57 +03:00
|
|
|
if (authorPeerId === client.selfPeerId.toB58String()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2021-01-16 12:28:01 +03:00
|
|
|
if (changes) {
|
|
|
|
syncClient.receiveChanges(changes);
|
2021-01-14 23:57:24 +03:00
|
|
|
}
|
2021-01-14 13:17:48 +03:00
|
|
|
});
|
|
|
|
|
2021-01-16 12:28:01 +03:00
|
|
|
syncClient.start();
|
|
|
|
|
2021-01-14 13:17:48 +03:00
|
|
|
// don't block
|
|
|
|
calls.getHistory(client).then((res) => {
|
2021-01-16 01:38:09 +03:00
|
|
|
for (let e of res) {
|
2021-01-16 12:28:01 +03:00
|
|
|
syncClient.receiveChanges(e.body);
|
2021-01-16 01:38:09 +03:00
|
|
|
}
|
2021-01-14 13:17:48 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
return () => {
|
2021-01-16 12:28:01 +03:00
|
|
|
unsub();
|
|
|
|
syncClient.stop();
|
2021-01-14 13:17:48 +03:00
|
|
|
};
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
const handleTextUpdate = (e: React.ChangeEvent<HTMLTextAreaElement>) => {
|
2021-01-16 12:28:01 +03:00
|
|
|
const newText = e.target.value;
|
|
|
|
setText(newText);
|
|
|
|
broadcastUpdates(newText, syncClient);
|
2021-01-14 13:17:48 +03:00
|
|
|
};
|
|
|
|
|
2021-01-16 16:25:28 +03:00
|
|
|
return <textarea spellCheck={false} className="code-editor" value={text} onChange={handleTextUpdate} />;
|
2021-01-14 13:17:48 +03:00
|
|
|
};
|