mirror of
https://github.com/pacnpal/thrillwiki_django_no_react.git
synced 2025-12-20 18:51:07 -05:00
Add comment and reply functionality with preview and notification templates
This commit is contained in:
203
static/js/collaboration-system.js
Normal file
203
static/js/collaboration-system.js
Normal file
@@ -0,0 +1,203 @@
|
||||
// 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;
|
||||
Reference in New Issue
Block a user