diff --git a/package-lock.json b/package-lock.json index cea2464..ffea4d0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,14 @@ { "name": "refactor-platform-fe", - "version": "0.1.0", + "version": "1.0.0-rc2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "refactor-platform-fe", - "version": "0.1.0", + "version": "1.0.0-rc2", "dependencies": { + "@hocuspocus/provider": "^2.15.0", "@radix-ui/react-alert-dialog": "^1.1.4", "@radix-ui/react-avatar": "^1.1.2", "@radix-ui/react-checkbox": "^1.1.3", @@ -32,6 +33,8 @@ "@tiptap/extension-bubble-menu": "^2.10.4", "@tiptap/extension-bullet-list": "^2.10.4", "@tiptap/extension-code-block-lowlight": "^2.10.4", + "@tiptap/extension-collaboration": "^2.10.4", + "@tiptap/extension-collaboration-cursor": "^2.10.4", "@tiptap/extension-heading": "^2.10.4", "@tiptap/extension-highlight": "^2.10.4", "@tiptap/extension-list-item": "^2.10.4", @@ -56,6 +59,10 @@ "tailwind-merge": "^2.5.5", "tailwindcss-animate": "^1.0.7", "ts-luxon": "^5.0.7-beta.0", + "y-prosemirror": "^1.2.15", + "y-protocols": "^1.0.6", + "y-webrtc": "^10.3.0", + "yjs": "^13.6.21", "zustand": "^5.0.2" }, "devDependencies": { @@ -200,6 +207,31 @@ "integrity": "sha512-kym7SodPp8/wloecOpcmSnWJsK7M0E5Wg8UcFA+uO4B9s5d0ywXOEro/8HM9x0rW+TljRzul/14UYz3TleT3ig==", "license": "MIT" }, + "node_modules/@hocuspocus/common": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/@hocuspocus/common/-/common-2.15.0.tgz", + "integrity": "sha512-xmapO5PnQvf3lYFWrrOaYPjmdrEIVYOpyjInuiCkCzkUmMQCZDVM3wXjPdMJbgAtQXEPUDVkwpr6dJTLjZgTTQ==", + "license": "MIT", + "dependencies": { + "lib0": "^0.2.87" + } + }, + "node_modules/@hocuspocus/provider": { + "version": "2.15.0", + "resolved": "https://registry.npmjs.org/@hocuspocus/provider/-/provider-2.15.0.tgz", + "integrity": "sha512-Zd1YYVIg1PYfxqMbwWlb89+R/pOGg+UQZWBr7u3g2RDOttdM8F9zzyUzm9XcI7CAGZAUvuqB/oiSsMyGxDsuNg==", + "license": "MIT", + "dependencies": { + "@hocuspocus/common": "^2.15.0", + "@lifeomic/attempt": "^3.0.2", + "lib0": "^0.2.87", + "ws": "^8.17.1" + }, + "peerDependencies": { + "y-protocols": "^1.0.6", + "yjs": "^13.6.8" + } + }, "node_modules/@humanwhocodes/config-array": { "version": "0.13.0", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", @@ -691,6 +723,12 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@lifeomic/attempt": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@lifeomic/attempt/-/attempt-3.1.0.tgz", + "integrity": "sha512-QZqem4QuAnAyzfz+Gj5/+SLxqwCAw2qmt7732ZXodr6VDWGeYLG6w1i/vYLa55JQM9wRuBKLmXmiZ2P0LtE5rw==", + "license": "MIT" + }, "node_modules/@next/env": { "version": "15.1.2", "resolved": "https://registry.npmjs.org/@next/env/-/env-15.1.2.tgz", @@ -2490,6 +2528,35 @@ "lowlight": "^2 || ^3" } }, + "node_modules/@tiptap/extension-collaboration": { + "version": "2.10.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-collaboration/-/extension-collaboration-2.10.4.tgz", + "integrity": "sha512-IvVK/KGG3A0r/Du9ISv06v0VkKXB81RbCK3b/FSkV8+GPQXOqJ9L3aQ4N1LO7ZX5Cb0RbfVgSMK8WH2MIl6xKQ==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "@tiptap/pm": "^2.7.0", + "y-prosemirror": "^1.2.11" + } + }, + "node_modules/@tiptap/extension-collaboration-cursor": { + "version": "2.10.4", + "resolved": "https://registry.npmjs.org/@tiptap/extension-collaboration-cursor/-/extension-collaboration-cursor-2.10.4.tgz", + "integrity": "sha512-U5FJnvIveqLxKZ9aLPgXj1EDzfFfLlHX6J6VZNGAc0QsK5rWCdiU7HWuG2hNTSjHayqh/2V+x30PTMc5EuCadg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/ueberdosis" + }, + "peerDependencies": { + "@tiptap/core": "^2.7.0", + "y-prosemirror": "^1.2.11" + } + }, "node_modules/@tiptap/extension-document": { "version": "2.10.4", "resolved": "https://registry.npmjs.org/@tiptap/extension-document/-/extension-document-2.10.4.tgz", @@ -3510,6 +3577,26 @@ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -3578,6 +3665,30 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -3908,7 +4019,6 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dev": true, "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -4086,6 +4196,12 @@ "url": "https://github.com/fb55/entities?sponsor=1" } }, + "node_modules/err-code": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-3.0.1.tgz", + "integrity": "sha512-GiaH0KJUewYok+eeY05IIgjtAe4Yltygk9Wqp1V5yVWLdhf0hYZchRjNIT9bb0mSwRcIusT3cx7PJUf3zEIfUA==", + "license": "MIT" + }, "node_modules/es-abstract": { "version": "1.23.5", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.5.tgz", @@ -4978,6 +5094,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-browser-rtc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-browser-rtc/-/get-browser-rtc-1.1.0.tgz", + "integrity": "sha512-MghbMJ61EJrRsDe7w1Bvqt3ZsBuqhce5nrn/XAwgwOXhcsz53/ltdxOse1h/8eKXj5slzxdsz56g5rzOFSGwfQ==", + "license": "MIT" + }, "node_modules/get-intrinsic": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", @@ -5251,6 +5373,26 @@ "node": ">=12.0.0" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -5310,7 +5452,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "dev": true, "license": "ISC" }, "node_modules/internal-slot": { @@ -5753,6 +5894,16 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, + "node_modules/isomorphic.js": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/isomorphic.js/-/isomorphic.js-0.2.5.tgz", + "integrity": "sha512-PIeMbHqMt4DnUP3MA/Flc0HElYjMXArsw1qwJZcm9sqR8mq3l8NYizFMty0pWwE/tzIGH3EKK5+jes5mAr85yw==", + "license": "MIT", + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + } + }, "node_modules/iterator.prototype": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.3.tgz", @@ -5908,6 +6059,27 @@ "node": ">= 0.8.0" } }, + "node_modules/lib0": { + "version": "0.2.99", + "resolved": "https://registry.npmjs.org/lib0/-/lib0-0.2.99.tgz", + "integrity": "sha512-vwztYuUf1uf/1zQxfzRfO5yzfNKhTtgOByCruuiQQxWQXnPb8Itaube5ylofcV0oM0aKal9Mv+S1s1Ky0UYP1w==", + "license": "MIT", + "dependencies": { + "isomorphic.js": "^0.2.4" + }, + "bin": { + "0ecdsa-generate-keypair": "bin/0ecdsa-generate-keypair.js", + "0gentesthtml": "bin/gentesthtml.js", + "0serve": "bin/0serve.js" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + } + }, "node_modules/lilconfig": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", @@ -6115,7 +6287,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/mz": { @@ -7007,6 +7178,15 @@ ], "license": "MIT" }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, "node_modules/react": { "version": "19.0.0", "resolved": "https://registry.npmjs.org/react/-/react-19.0.0.tgz", @@ -7133,6 +7313,20 @@ "pify": "^2.3.0" } }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/readdirp": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.0.2.tgz", @@ -7324,6 +7518,26 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/safe-regex-test": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", @@ -7517,6 +7731,35 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/simple-peer": { + "version": "9.11.1", + "resolved": "https://registry.npmjs.org/simple-peer/-/simple-peer-9.11.1.tgz", + "integrity": "sha512-D1SaWpOW8afq1CZGWB8xTfrT3FekjQmPValrqncJMX7QFl8YwhrPTZvMCANLtgBwwdS+7zURyqxDDEmY558tTw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "buffer": "^6.0.3", + "debug": "^4.3.2", + "err-code": "^3.0.1", + "get-browser-rtc": "^1.1.0", + "queue-microtask": "^1.2.3", + "randombytes": "^2.1.0", + "readable-stream": "^3.6.0" + } + }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -7544,6 +7787,15 @@ "node": ">=10.0.0" } }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, "node_modules/string-width": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", @@ -8547,6 +8799,98 @@ "dev": true, "license": "ISC" }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y-prosemirror": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/y-prosemirror/-/y-prosemirror-1.2.15.tgz", + "integrity": "sha512-XDdrytq2M5bIy3qusQvfRclLu2eWZYPA+BbGWAb9FFWEhOB5FCrnzez2vsA+gvAd0FJTAcr89mjJ5g45r0j7TQ==", + "license": "MIT", + "dependencies": { + "lib0": "^0.2.42" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + }, + "peerDependencies": { + "prosemirror-model": "^1.7.1", + "prosemirror-state": "^1.2.3", + "prosemirror-view": "^1.9.10", + "y-protocols": "^1.0.1", + "yjs": "^13.5.38" + } + }, + "node_modules/y-protocols": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/y-protocols/-/y-protocols-1.0.6.tgz", + "integrity": "sha512-vHRF2L6iT3rwj1jub/K5tYcTT/mEYDUppgNPXwp8fmLpui9f7Yeq3OEtTLVF012j39QnV+KEQpNqoN7CWU7Y9Q==", + "license": "MIT", + "dependencies": { + "lib0": "^0.2.85" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + }, + "peerDependencies": { + "yjs": "^13.0.0" + } + }, + "node_modules/y-webrtc": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/y-webrtc/-/y-webrtc-10.3.0.tgz", + "integrity": "sha512-KalJr7dCgUgyVFxoG3CQYbpS0O2qybegD0vI4bYnYHI0MOwoVbucED3RZ5f2o1a5HZb1qEssUKS0H/Upc6p1lA==", + "license": "MIT", + "dependencies": { + "lib0": "^0.2.42", + "simple-peer": "^9.11.0", + "y-protocols": "^1.0.6" + }, + "bin": { + "y-webrtc-signaling": "bin/server.js" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + }, + "optionalDependencies": { + "ws": "^8.14.2" + }, + "peerDependencies": { + "yjs": "^13.6.8" + } + }, "node_modules/yaml": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.6.1.tgz", @@ -8559,6 +8903,23 @@ "node": ">= 14" } }, + "node_modules/yjs": { + "version": "13.6.21", + "resolved": "https://registry.npmjs.org/yjs/-/yjs-13.6.21.tgz", + "integrity": "sha512-/fzzyeCAfr3Qwx1D71zvumm64x+Q5MEFel6EhWlA1IBFxWPb7tei4J2a8CJyjpYHfVrRij5q3RJTK9W2Iqjouw==", + "license": "MIT", + "dependencies": { + "lib0": "^0.2.98" + }, + "engines": { + "node": ">=16.0.0", + "npm": ">=8.0.0" + }, + "funding": { + "type": "GitHub Sponsors ❤", + "url": "https://github.com/sponsors/dmonad" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index b587f26..dd622ff 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@hocuspocus/provider": "^2.15.0", "@radix-ui/react-alert-dialog": "^1.1.4", "@radix-ui/react-avatar": "^1.1.2", "@radix-ui/react-checkbox": "^1.1.3", @@ -33,6 +34,8 @@ "@tiptap/extension-bubble-menu": "^2.10.4", "@tiptap/extension-bullet-list": "^2.10.4", "@tiptap/extension-code-block-lowlight": "^2.10.4", + "@tiptap/extension-collaboration": "^2.10.4", + "@tiptap/extension-collaboration-cursor": "^2.10.4", "@tiptap/extension-heading": "^2.10.4", "@tiptap/extension-highlight": "^2.10.4", "@tiptap/extension-list-item": "^2.10.4", @@ -57,6 +60,10 @@ "tailwind-merge": "^2.5.5", "tailwindcss-animate": "^1.0.7", "ts-luxon": "^5.0.7-beta.0", + "y-prosemirror": "^1.2.15", + "y-protocols": "^1.0.6", + "y-webrtc": "^10.3.0", + "yjs": "^13.6.21", "zustand": "^5.0.2" }, "devDependencies": { @@ -73,7 +80,7 @@ }, "overrides": { "react": "$react", - "react-dom": "$react-dom", + "react-dom": "$react-dom", "@types/react": "19.0.2", "@types/react-dom": "19.0.2" } diff --git a/src/app/coaching-sessions/[id]/page.tsx b/src/app/coaching-sessions/[id]/page.tsx index 0b648f3..9acb591 100644 --- a/src/app/coaching-sessions/[id]/page.tsx +++ b/src/app/coaching-sessions/[id]/page.tsx @@ -76,11 +76,11 @@ export default function CoachingSessionsPage() { } }; - useEffect(() => { - if (!currentCoachingSessionId) return; + // useEffect(() => { + // if (!currentCoachingSessionId) return; - fetchNoteData(); - }, [currentCoachingSessionId]); + // fetchNoteData(); + // }, [currentCoachingSessionId]); const setEditorContent = (content: string) => { editorRef.current?.setContent(`${content}`); @@ -100,33 +100,37 @@ export default function CoachingSessionsPage() { console.debug("value (before update/create): " + value); console.debug("--------------------------------"); - if (!isLoading && note.id && currentCoachingSessionId && userId) { - updateNote(note.id, currentCoachingSessionId, userId, value) - .then((updatedNote) => { - setNote(updatedNote); - console.trace("Updated Note: " + noteToString(updatedNote)); - setSyncStatus("All changes saved"); - }) - .catch((err) => { - setSyncStatus("Failed to save changes"); - console.error("Failed to update Note: " + err); - }); - } else if (!isLoading && !note.id && currentCoachingSessionId && userId) { - createNote(currentCoachingSessionId, userId, value) - .then((createdNote) => { - setNote(createdNote); - console.trace("Newly created Note: " + noteToString(createdNote)); - setSyncStatus("All changes saved"); - }) - .catch((err) => { - setSyncStatus("Failed to save changes"); - console.error("Failed to create new Note: " + err); - }); - } else { - console.error( - "Could not update or create a Note since coachingSession.id or userId are not set." - ); - } + // if (!isLoading && note.id && currentCoachingSessionId && userId) { + // updateNote(note.id, currentCoachingSessionId, userId, value) + // .then((updatedNote) => { + // setNote(updatedNote); + // console.trace("Updated Note: " + noteToString(updatedNote)); + // setSyncStatus("All changes saved"); + // }) + // .catch((err) => { + // setSyncStatus("Failed to save changes"); + // console.error("Failed to update Note: " + err); + // }); + // } else if (!isLoading && !note.id && currentCoachingSessionId && userId) { + // createNote(currentCoachingSessionId, userId, value) + // .then((createdNote) => { + // setNote(createdNote); + // console.trace("Newly created Note: " + noteToString(createdNote)); + // setSyncStatus("All changes saved"); + // }) + // .catch((err) => { + // setSyncStatus("Failed to save changes"); + // console.error("Failed to create new Note: " + err); + // }); + // } else { + // console.error( + // "Could not update or create a Note since coachingSession.id or userId are not set." + // ); + // } + }; + + const handleOnSynced = () => { + setSyncStatus("Notes synced"); }; const handleKeyDown = () => { @@ -187,6 +191,7 @@ export default function CoachingSessionsPage() { ref={editorRef} value={note.body} onChange={handleOnChange} + onSynced={handleOnSynced} onKeyDown={handleKeyDown} >

{syncStatus}

diff --git a/src/components/ui/coaching-sessions/coaching-notes.tsx b/src/components/ui/coaching-sessions/coaching-notes.tsx index b270bf9..a05fda5 100644 --- a/src/components/ui/coaching-sessions/coaching-notes.tsx +++ b/src/components/ui/coaching-sessions/coaching-notes.tsx @@ -11,11 +11,12 @@ export interface EditorRef { interface CoachingNotesProps { value: string; onChange: (content: string) => void; + onSynced?: () => void; onKeyDown: () => void; } const CoachingNotes = forwardRef( - ({ value, onChange, onKeyDown }, ref) => { + ({ value, onChange, onSynced, onKeyDown }, ref) => { const WAIT_INTERVAL = 1000; const timerRef = useRef(undefined); const [note, setNote] = useState(value); @@ -43,6 +44,12 @@ const CoachingNotes = forwardRef( [onKeyDown, onChange, WAIT_INTERVAL] ); + const handleSessionNoteSynced = useCallback(() => { + if (onSynced) { + onSynced(); + } + }, [onSynced]); + useEffect(() => { return () => { if (timerRef.current) { @@ -56,6 +63,7 @@ const CoachingNotes = forwardRef( ref={ref} editorContent={note} onChange={handleSessionNoteChange} + onSynced={handleSessionNoteSynced} /> ); } diff --git a/src/components/ui/coaching-sessions/tiptap-editor.tsx b/src/components/ui/coaching-sessions/tiptap-editor.tsx index e027758..898225d 100644 --- a/src/components/ui/coaching-sessions/tiptap-editor.tsx +++ b/src/components/ui/coaching-sessions/tiptap-editor.tsx @@ -2,6 +2,13 @@ import { useEditor, EditorContent, ReactNodeViewRenderer } from "@tiptap/react"; +import Collaboration from "@tiptap/extension-collaboration"; +import CollaborationCursor from "@tiptap/extension-collaboration-cursor"; +import { WebrtcProvider } from "y-webrtc"; +import * as Y from "yjs"; + +import { TiptapCollabProvider } from "@hocuspocus/provider"; + import Bold from "@tiptap/extension-bold"; import BulletList from "@tiptap/extension-bullet-list"; import Document from "@tiptap/extension-document"; @@ -29,7 +36,7 @@ import { Braces, } from "lucide-react"; import { Button } from "@/components/ui/button"; -import { forwardRef, useImperativeHandle } from "react"; +import { forwardRef, useEffect, useImperativeHandle } from "react"; import { EditorRef } from "./coaching-notes"; @@ -52,13 +59,20 @@ lowlight.register("css", css); lowlight.register("js", js); lowlight.register("ts", ts); +const doc = new Y.Doc(); +// const collabCursorProvider = new WebrtcProvider( +// "tiptap-collaboration-cursor-extension", +// doc +// ); + interface TipTapProps { editorContent: string; onChange: (content: string) => void; + onSynced?: () => void; } const TipTapEditor = forwardRef( - ({ editorContent, onChange }, ref) => { + ({ editorContent, onChange, onSynced }, ref) => { const editor = useEditor( { extensions: [ @@ -79,6 +93,16 @@ const TipTapEditor = forwardRef( Strike, Text, Underline, + Collaboration.configure({ + document: doc, // Configure Y.Doc for collaboration + }), + // CollaborationCursor.configure({ + // provider: collabCursorProvider, + // user: { + // name: "Jim Hodapp", + // color: "#ffcc00", + // }, + // }), ], autofocus: false, @@ -99,6 +123,12 @@ const TipTapEditor = forwardRef( [] ); + // editor?.commands.updateUser({ + // name: "John Doe", + // color: "#000000", + // avatar: "https://unavatar.io/github/ueberdosis", + // }); + useImperativeHandle(ref, () => ({ setContent: (content: string) => { editor?.commands.setContent(JSON.parse(content)); @@ -109,6 +139,30 @@ const TipTapEditor = forwardRef( }, })); + // Connect to your Collaboration server + useEffect(() => { + const provider = new TiptapCollabProvider({ + name: "refactor.test.document.name", // Unique document identifier for syncing. This is your document name. + //appId: "", // Your Cloud Dashboard AppID or ... + baseUrl: "ws://127.0.0.1:8080", // ... `baseURL` for on-premises + token: "", // Your JWT token + document: doc, + onOpen() { + console.log("WebSocket connection opened."); + }, + onConnect() { + console.log("Connected to the server."); + }, + }); + + provider.on("synced", () => { + console.debug("provider.on('synced')"); + if (onSynced) { + onSynced(); + } + }); + }, []); + if (!editor) { return null; }