Files
course-craft-service/apps/web/src/app/(dashboard)/dashboard/groups/[groupId]/page.tsx
2026-02-06 14:53:52 +00:00

101 lines
3.4 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

'use client';
import { useEffect, useRef, useState } from 'react';
import { useParams } from 'next/navigation';
import { io, Socket } from 'socket.io-client';
import { Send } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { api } from '@/lib/api';
import { getWsBaseUrl } from '@/lib/ws';
export default function InviteGroupPage() {
const params = useParams();
const groupId = params?.groupId as string;
const [messages, setMessages] = useState<any[]>([]);
const [members, setMembers] = useState<any[]>([]);
const [message, setMessage] = useState('');
const socketRef = useRef<Socket | null>(null);
useEffect(() => {
if (!groupId) return;
(async () => {
await api.joinGroupByInvite(groupId).catch(() => null);
const [msgs, mbrs] = await Promise.all([
api.getGroupMessages(groupId).catch(() => []),
api.getGroupMembers(groupId).catch(() => []),
]);
setMessages(msgs);
setMembers(mbrs);
})();
}, [groupId]);
useEffect(() => {
if (!groupId) return;
const token =
typeof window !== 'undefined' ? sessionStorage.getItem('coursecraft_api_token') || undefined : undefined;
const socket = io(`${getWsBaseUrl()}/ws/course-groups`, {
transports: ['websocket'],
auth: { token },
});
socketRef.current = socket;
socket.emit('groups:join', { groupId });
socket.on('groups:new-message', (msg: any) => setMessages((prev) => [...prev, msg]));
return () => {
socket.disconnect();
socketRef.current = null;
};
}, [groupId]);
const send = async () => {
if (!groupId || !message.trim()) return;
await api.sendGroupMessage(groupId, message.trim());
setMessage('');
};
return (
<div className="grid gap-4 lg:grid-cols-[1fr_320px]">
<Card className="min-h-[460px]">
<CardHeader>
<CardTitle>Групповой чат курса</CardTitle>
</CardHeader>
<CardContent className="flex h-[400px] flex-col">
<div className="flex-1 overflow-auto space-y-2 pr-2">
{messages.map((msg) => (
<div key={msg.id} className="rounded-md border p-2 text-sm">
<p className="font-medium">{msg.user?.name || 'Участник'}</p>
<p>{msg.content}</p>
</div>
))}
</div>
<div className="mt-3 flex gap-2">
<input
value={message}
onChange={(e) => setMessage(e.target.value)}
className="flex-1 rounded-md border bg-background px-3 py-2 text-sm"
placeholder="Сообщение"
/>
<Button onClick={send}>
<Send className="h-4 w-4" />
</Button>
</div>
</CardContent>
</Card>
<Card>
<CardHeader>
<CardTitle>Участники ({members.length})</CardTitle>
</CardHeader>
<CardContent className="space-y-2">
{members.map((member) => (
<div key={member.id} className="rounded-md border p-2 text-sm">
<p className="font-medium">{member.user?.name || member.user?.email}</p>
<p className="text-xs text-muted-foreground">{member.role}</p>
</div>
))}
</CardContent>
</Card>
</div>
);
}