duelfi_admin/app/dashboard/chat/page.tsx
2025-06-08 22:04:00 +05:30

160 lines
4.8 KiB
TypeScript

'use client';
import { useEffect, useState } from 'react';
import { io, Socket } from 'socket.io-client';
import { Button } from '@/components/ui/button';
import { Input } from '@/components/ui/input';
import { Card } from '@/components/ui/card';
import { User, fetchUsers } from '@/utils/api';
interface ChatMessage {
id: string;
user: string;
message: string;
timestamp: number;
}
export default function ChatModeration() {
const [messages, setMessages] = useState<ChatMessage[]>([]);
const [socket, setSocket] = useState<Socket | null>(null);
const [editingMessage, setEditingMessage] = useState<string | null>(null);
const [editText, setEditText] = useState('');
const [users, setUsers] = useState<User[]>([]);
const [loading, setLoading] = useState(true);
useEffect(() => {
const loadUsers = async () => {
try {
const usersData = await fetchUsers();
setUsers(usersData);
} catch (error) {
console.error('Error loading users:', error);
} finally {
setLoading(false);
}
};
loadUsers();
}, []);
useEffect(() => {
const newSocket = io('https://wschat.duelfi.io');
setSocket(newSocket);
newSocket.on('recent messages', (recentMessages: ChatMessage[]) => {
setMessages(recentMessages);
});
newSocket.on('chat message', (message: ChatMessage) => {
setMessages(prev => [...prev, message]);
});
newSocket.on('message edited', ({ messageId, newMessage }: { messageId: string; newMessage: string }) => {
setMessages(prev =>
prev.map(msg =>
msg.id === messageId ? { ...msg, message: newMessage } : msg
)
);
});
newSocket.on('message deleted', (messageId: string) => {
setMessages(prev => prev.filter(msg => msg.id !== messageId));
});
return () => {
newSocket.close();
};
}, []);
const getUserDisplayName = (userId: string): string => {
const user = users.find(u => u.id === userId);
if (user?.username) {
return user.username;
}
// If no username found, return a truncated version of the ID
return userId.startsWith('did:privy:')
? `User ${userId.slice(-4)}`
: userId;
};
const handleEdit = (message: ChatMessage) => {
setEditingMessage(message.id);
setEditText(message.message);
};
const handleSaveEdit = (messageId: string) => {
if (socket) {
socket.emit('edit message', {
messageId,
newMessage: editText
});
setEditingMessage(null);
}
};
const handleDelete = (messageId: string) => {
if (socket && confirm('Are you sure you want to delete this message?')) {
socket.emit('delete message', messageId);
}
};
if (loading) {
return (
<div className="flex items-center justify-center min-h-screen">
<div className="text-lg text-[var(--text-primary)]">Loading...</div>
</div>
);
}
return (
<div className="container mx-auto p-4">
<h1 className="text-2xl font-bold mb-4">Chat Moderation</h1>
<div className="space-y-4">
{messages.map((message) => (
<Card key={message.id} className="p-4">
<div className="flex justify-between items-start">
<div className="flex-1">
<div className="text-sm text-[var(--text-secondary)]">
{getUserDisplayName(message.user)} {new Date(message.timestamp).toLocaleString()}
</div>
{editingMessage === message.id ? (
<div className="mt-2 flex gap-2">
<Input
value={editText}
onChange={(e: React.ChangeEvent<HTMLInputElement>) => setEditText(e.target.value)}
className="flex-1"
/>
<Button onClick={() => handleSaveEdit(message.id)}>Save</Button>
<Button variant="outline" onClick={() => setEditingMessage(null)}>
Cancel
</Button>
</div>
) : (
<div className="mt-1 text-[var(--text-primary)]">{message.message}</div>
)}
</div>
{editingMessage !== message.id && (
<div className="flex gap-2 ml-4">
<Button
variant="outline"
size="sm"
onClick={() => handleEdit(message)}
>
Edit
</Button>
<Button
variant="destructive"
size="sm"
onClick={() => handleDelete(message.id)}
>
Delete
</Button>
</div>
)}
</div>
</Card>
))}
</div>
</div>
);
}