Admin WebSocket Connection
Establishes a real-time WebSocket connection for admin chat functionality.
WebSocket URL
ws://localhost:8000/v1/chat/ws/admin/?token=<auth_token>
wss://api.luxmart.site/v1/chat/ws/admin/?token=<auth_token>
Authentication
Pass the admin's authentication token as a query parameter:
Note: Only users with admin role can connect.
Connection Lifecycle
1. Connect
const token = "your_admin_token_here";
const ws = new WebSocket(`ws://localhost:8000/v1/chat/ws/admin/?token=${encodeURIComponent(token)}`);
2. Connection Events
On Open:
On Message:
ws.onmessage = (event) => {
const payload = JSON.parse(event.data);
// Handle different event types
};
On Close:
On Error:
Event Types
1. Receiving Messages
Event Type: message
Payload:
{
"type": "message",
"payload": {
"message": {
"id": 124,
"session_id": 1,
"sender_type": "store",
"content": "I have a question about shipping",
"is_read": false,
"created_at": "2025-12-16T10:25:00Z"
}
}
}
Important: Admins receive messages from ALL their claimed sessions, not just the active one.
Example Handler:
if (payload.type === "message") {
const message = payload.payload.message;
if (message.session_id === activeSessionId) {
// Display in current chat view
displayMessage(message);
} else {
// Update session list to show unread message
updateSessionList(message.session_id);
}
}
2. New Message Notification
Event Type: new_notification
Sent when a store sends a message while admin is on a different page (not on messages page).
Payload:
Example Handler:
3. Session Updates
Event Type: session_update
Sent when a new session is created or session status changes.
Payload:
{
"type": "session_update",
"payload": {
"session": {
"id": 5,
"store_id": 10,
"status": "open",
"created_at": "2025-12-16T11:00:00Z"
}
}
}
4. Typing Indicator
Event Type: typing
Indicates when a store is typing.
Payload:
Example Handler:
if (payload.type === "typing") {
if (payload.payload.session_id === activeSessionId) {
showTypingIndicator(payload.payload.is_typing);
}
}
5. Error Messages
Event Type: error
Payload:
Sending Messages
1. Send Text Message
Send via WebSocket:
ws.send(JSON.stringify({
type: "message",
payload: {
session_id: 1,
content: "I can help you with that!"
}
}));
Required Fields:
- session_id: The ID of the chat session
- content: The message text
Response:
You'll receive the message back with full details including id and created_at.
2. Send Typing Indicator
// Admin started typing
ws.send(JSON.stringify({
type: "typing",
payload: {
session_id: 1,
is_typing: true
}
}));
// Admin stopped typing
setTimeout(() => {
ws.send(JSON.stringify({
type: "typing",
payload: {
session_id: 1,
is_typing: false
}
}));
}, 3000);
Complete Example
class AdminChat {
constructor(token) {
this.token = token;
this.ws = null;
this.reconnectAttempts = 0;
this.maxReconnectAttempts = 5;
this.activeSessions = new Map();
}
connect() {
const wsUrl = `ws://localhost:8000/v1/chat/ws/admin/?token=${encodeURIComponent(this.token)}`;
this.ws = new WebSocket(wsUrl);
this.ws.onopen = () => {
console.log("Admin chat connected");
this.reconnectAttempts = 0;
};
this.ws.onmessage = (event) => {
const payload = JSON.parse(event.data);
this.handleEvent(payload);
};
this.ws.onclose = () => {
console.log("Admin chat disconnected");
this.reconnect();
};
this.ws.onerror = (error) => {
console.error("WebSocket error:", error);
};
}
handleEvent(payload) {
switch (payload.type) {
case "message":
if (payload.payload?.message) {
this.handleMessage(payload.payload.message);
}
break;
case "new_notification":
if (payload.payload?.count !== undefined) {
this.updateNotificationCount(payload.payload.count);
}
break;
case "session_update":
if (payload.payload?.session) {
this.handleSessionUpdate(payload.payload.session);
}
break;
case "typing":
if (payload.payload?.session_id) {
this.handleTyping(
payload.payload.session_id,
payload.payload.is_typing
);
}
break;
case "error":
console.error("Chat error:", payload.payload?.message);
break;
}
}
handleMessage(message) {
// Store message
if (!this.activeSessions.has(message.session_id)) {
this.activeSessions.set(message.session_id, []);
}
this.activeSessions.get(message.session_id).push(message);
// Display or update UI
if (message.sender_type === "store") {
this.displayStoreMessage(message);
}
}
sendMessage(sessionId, content) {
if (this.ws?.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({
type: "message",
payload: {
session_id: sessionId,
content: content
}
}));
}
}
sendTyping(sessionId, isTyping) {
if (this.ws?.readyState === WebSocket.OPEN) {
this.ws.send(JSON.stringify({
type: "typing",
payload: {
session_id: sessionId,
is_typing: isTyping
}
}));
}
}
reconnect() {
if (this.reconnectAttempts < this.maxReconnectAttempts) {
this.reconnectAttempts++;
const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
console.log(`Reconnecting in ${delay}ms...`);
setTimeout(() => this.connect(), delay);
}
}
disconnect() {
if (this.ws) {
this.ws.close();
}
}
displayStoreMessage(message) {
// Implement your UI logic here
console.log(`Store (Session ${message.session_id}): ${message.content}`);
}
updateNotificationCount(count) {
// Update notification badge
console.log(`Unread notifications: ${count}`);
}
handleSessionUpdate(session) {
// Update session list
console.log(`Session updated: ${session.id} - ${session.status}`);
}
handleTyping(sessionId, isTyping) {
// Show/hide typing indicator for specific session
console.log(`Session ${sessionId}: typing=${isTyping}`);
}
}
// Usage
const adminChat = new AdminChat(adminToken);
adminChat.connect();
// Send message to a specific session
adminChat.sendMessage(1, "Hello! How can I help you today?");
// Send typing indicator
adminChat.sendTyping(1, true);
Managing Multiple Sessions
Admins can handle multiple chat sessions simultaneously:
1. Track Active Sessions
// Store messages per session
const sessionMessages = new Map();
ws.onmessage = (event) => {
const payload = JSON.parse(event.data);
if (payload.type === "message") {
const msg = payload.payload.message;
if (!sessionMessages.has(msg.session_id)) {
sessionMessages.set(msg.session_id, []);
}
sessionMessages.get(msg.session_id).push(msg);
// Update UI based on active session
if (msg.session_id === currentActiveSessionId) {
displayMessage(msg);
} else {
showUnreadIndicator(msg.session_id);
}
}
};
2. Switch Between Sessions
function switchToSession(sessionId) {
currentActiveSessionId = sessionId;
// Load message history for this session
const messages = sessionMessages.get(sessionId) || [];
displayMessages(messages);
// Mark messages as read
markSessionMessagesAsRead(sessionId);
}
Notification System
When the admin is NOT on the messages page, they receive notifications for new messages:
1. Listen for Notifications
if (payload.type === "new_notification") {
const unreadCount = payload.payload.count;
// Update badge on bell icon
updateBadge(unreadCount);
// Optionally show browser notification
if (Notification.permission === "granted") {
new Notification("New Message", {
body: "You have a new message from a store",
icon: "/notification-icon.png"
});
}
}
2. Fetch Notification Details
Use the REST API to get full notification details:
// GET /v1/chat/admin/notifications/
fetch("/v1/chat/admin/notifications/", {
headers: {
"Authorization": `Token ${adminToken}`
}
})
.then(res => res.json())
.then(data => {
displayNotifications(data.data);
});
Best Practices
- Always URL-encode the token when passing as query parameter
- Implement auto-reconnection with exponential backoff
- Handle multiple sessions by tracking messages per session
- Update session lists when receiving messages from non-active sessions
- Show typing indicators only for the active session
- Mark messages as read when viewing a session
- Handle notifications when admin is on other pages
- Buffer messages during disconnection
- Implement UI feedback for connection status
- Auto-scroll to latest message in active session