your message
This commit is contained in:
100
apps/web/src/app/(dashboard)/dashboard/groups/[groupId]/page.tsx
Normal file
100
apps/web/src/app/(dashboard)/dashboard/groups/[groupId]/page.tsx
Normal file
@ -0,0 +1,100 @@
|
||||
'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>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user