mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 12:51:09 -05:00
203 lines
6.0 KiB
JavaScript
203 lines
6.0 KiB
JavaScript
// Collaboration System
|
|
|
|
class CollaborationSystem {
|
|
constructor(options = {}) {
|
|
this.onCommentAdded = options.onCommentAdded || (() => {});
|
|
this.onCommentResolved = options.onCommentResolved || (() => {});
|
|
this.onThreadCreated = options.onThreadCreated || (() => {});
|
|
this.socket = null;
|
|
this.currentUser = options.currentUser;
|
|
}
|
|
|
|
initialize(socketUrl) {
|
|
this.socket = new WebSocket(socketUrl);
|
|
this.setupSocketHandlers();
|
|
}
|
|
|
|
setupSocketHandlers() {
|
|
if (!this.socket) return;
|
|
|
|
this.socket.addEventListener('open', () => {
|
|
console.log('Collaboration system connected');
|
|
});
|
|
|
|
this.socket.addEventListener('message', (event) => {
|
|
try {
|
|
const data = JSON.parse(event.data);
|
|
this.handleEvent(data);
|
|
} catch (error) {
|
|
console.error('Failed to parse collaboration event:', error);
|
|
}
|
|
});
|
|
|
|
this.socket.addEventListener('close', () => {
|
|
console.log('Collaboration system disconnected');
|
|
// Attempt to reconnect after delay
|
|
setTimeout(() => this.reconnect(), 5000);
|
|
});
|
|
|
|
this.socket.addEventListener('error', (error) => {
|
|
console.error('Collaboration system error:', error);
|
|
});
|
|
}
|
|
|
|
handleEvent(event) {
|
|
switch (event.type) {
|
|
case 'comment_added':
|
|
this.onCommentAdded(event.data);
|
|
break;
|
|
case 'comment_resolved':
|
|
this.onCommentResolved(event.data);
|
|
break;
|
|
case 'thread_created':
|
|
this.onThreadCreated(event.data);
|
|
break;
|
|
default:
|
|
console.warn('Unknown collaboration event:', event.type);
|
|
}
|
|
}
|
|
|
|
async createCommentThread(changeId, anchor, initialComment) {
|
|
try {
|
|
const response = await fetch('/vcs/comments/threads/create/', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': this.getCsrfToken()
|
|
},
|
|
body: JSON.stringify({
|
|
change_id: changeId,
|
|
anchor: anchor,
|
|
initial_comment: initialComment
|
|
})
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Failed to create comment thread');
|
|
}
|
|
|
|
const thread = await response.json();
|
|
|
|
// Notify other users through WebSocket
|
|
this.broadcastEvent({
|
|
type: 'thread_created',
|
|
data: {
|
|
thread_id: thread.id,
|
|
change_id: changeId,
|
|
anchor: anchor,
|
|
author: this.currentUser,
|
|
timestamp: new Date().toISOString()
|
|
}
|
|
});
|
|
|
|
return thread;
|
|
} catch (error) {
|
|
console.error('Error creating comment thread:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async addComment(threadId, content, parentId = null) {
|
|
try {
|
|
const response = await fetch('/vcs/comments/create/', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': this.getCsrfToken()
|
|
},
|
|
body: JSON.stringify({
|
|
thread_id: threadId,
|
|
content: content,
|
|
parent_id: parentId
|
|
})
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Failed to add comment');
|
|
}
|
|
|
|
const comment = await response.json();
|
|
|
|
// Notify other users through WebSocket
|
|
this.broadcastEvent({
|
|
type: 'comment_added',
|
|
data: {
|
|
comment_id: comment.id,
|
|
thread_id: threadId,
|
|
parent_id: parentId,
|
|
author: this.currentUser,
|
|
content: content,
|
|
timestamp: new Date().toISOString()
|
|
}
|
|
});
|
|
|
|
return comment;
|
|
} catch (error) {
|
|
console.error('Error adding comment:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
async resolveThread(threadId) {
|
|
try {
|
|
const response = await fetch(`/vcs/comments/threads/${threadId}/resolve/`, {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': this.getCsrfToken()
|
|
}
|
|
});
|
|
|
|
if (!response.ok) {
|
|
throw new Error('Failed to resolve thread');
|
|
}
|
|
|
|
const result = await response.json();
|
|
|
|
// Notify other users through WebSocket
|
|
this.broadcastEvent({
|
|
type: 'comment_resolved',
|
|
data: {
|
|
thread_id: threadId,
|
|
resolver: this.currentUser,
|
|
timestamp: new Date().toISOString()
|
|
}
|
|
});
|
|
|
|
return result;
|
|
} catch (error) {
|
|
console.error('Error resolving thread:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
broadcastEvent(event) {
|
|
if (this.socket && this.socket.readyState === WebSocket.OPEN) {
|
|
this.socket.send(JSON.stringify(event));
|
|
}
|
|
}
|
|
|
|
reconnect() {
|
|
if (this.socket) {
|
|
try {
|
|
this.socket.close();
|
|
} catch (error) {
|
|
console.error('Error closing socket:', error);
|
|
}
|
|
}
|
|
this.initialize(this.socketUrl);
|
|
}
|
|
|
|
getCsrfToken() {
|
|
return document.querySelector('[name=csrfmiddlewaretoken]').value;
|
|
}
|
|
|
|
disconnect() {
|
|
if (this.socket) {
|
|
this.socket.close();
|
|
this.socket = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
export default CollaborationSystem; |