观影室增加屏幕共享
This commit is contained in:
+95
-18
@@ -10,7 +10,7 @@ import { getAuthInfoFromBrowserCookie } from '@/lib/auth';
|
||||
import PageLayout from '@/components/PageLayout';
|
||||
import { useWatchRoomContext } from '@/components/WatchRoomProvider';
|
||||
|
||||
import type { Room } from '@/types/watch-room';
|
||||
import type { Room, RoomType } from '@/types/watch-room';
|
||||
|
||||
type TabType = 'create' | 'join' | 'list';
|
||||
|
||||
@@ -34,6 +34,7 @@ export default function WatchRoomPage() {
|
||||
description: '',
|
||||
password: '',
|
||||
isPublic: true,
|
||||
roomType: 'sync' as RoomType,
|
||||
});
|
||||
|
||||
// 加入房间表单
|
||||
@@ -49,26 +50,30 @@ export default function WatchRoomPage() {
|
||||
const [joinLoading, setJoinLoading] = useState(false);
|
||||
|
||||
// 加载房间列表
|
||||
const loadRooms = async () => {
|
||||
const loadRooms = async (showLoading = false) => {
|
||||
if (!isConnected) return;
|
||||
|
||||
setLoading(true);
|
||||
if (showLoading) {
|
||||
setLoading(true);
|
||||
}
|
||||
try {
|
||||
const roomList = await getRoomList();
|
||||
setRooms(roomList);
|
||||
} catch (error) {
|
||||
console.error('[WatchRoom] Failed to load rooms:', error);
|
||||
} finally {
|
||||
setLoading(false);
|
||||
if (showLoading) {
|
||||
setLoading(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// 切换到房间列表 tab 时加载房间
|
||||
useEffect(() => {
|
||||
if (activeTab === 'list') {
|
||||
loadRooms();
|
||||
loadRooms(true);
|
||||
// 每5秒刷新一次
|
||||
const interval = setInterval(loadRooms, 5000);
|
||||
const interval = setInterval(() => loadRooms(false), 5000);
|
||||
return () => clearInterval(interval);
|
||||
}
|
||||
}, [activeTab, isConnected]);
|
||||
@@ -88,6 +93,7 @@ export default function WatchRoomPage() {
|
||||
description: createForm.description.trim(),
|
||||
password: createForm.password.trim() || undefined,
|
||||
isPublic: createForm.isPublic,
|
||||
roomType: createForm.roomType,
|
||||
userName: currentUsername,
|
||||
});
|
||||
|
||||
@@ -97,6 +103,7 @@ export default function WatchRoomPage() {
|
||||
description: '',
|
||||
password: '',
|
||||
isPublic: true,
|
||||
roomType: 'sync',
|
||||
});
|
||||
} catch (error: any) {
|
||||
alert(error.message || '创建房间失败');
|
||||
@@ -141,6 +148,11 @@ export default function WatchRoomPage() {
|
||||
useEffect(() => {
|
||||
if (!currentRoom || isOwner) return;
|
||||
|
||||
if (currentRoom.roomType === 'screen') {
|
||||
router.push('/watch-room/screen');
|
||||
return;
|
||||
}
|
||||
|
||||
// 房员加入房间后,不立即跳转
|
||||
// 而是监听 play:change 或 live:change 事件(说明房主正在活跃使用)
|
||||
// 这样可以避免房主已经离开play页面但状态未清除的情况
|
||||
@@ -153,6 +165,8 @@ export default function WatchRoomPage() {
|
||||
useEffect(() => {
|
||||
if (!currentRoom || isOwner) return;
|
||||
|
||||
if (currentRoom.roomType === 'screen') return;
|
||||
|
||||
const handlePlayChange = (state: any) => {
|
||||
if (state.type === 'play') {
|
||||
const params = new URLSearchParams({
|
||||
@@ -196,6 +210,13 @@ export default function WatchRoomPage() {
|
||||
}
|
||||
}, [currentRoom, isOwner, router, socket]);
|
||||
|
||||
// 屏幕共享房间创建/加入后直接进入共享页
|
||||
useEffect(() => {
|
||||
if (currentRoom?.roomType === 'screen') {
|
||||
router.push('/watch-room/screen');
|
||||
}
|
||||
}, [currentRoom?.id, currentRoom?.roomType, router]);
|
||||
|
||||
// 从房间列表加入房间
|
||||
const handleJoinFromList = (room: Room) => {
|
||||
setJoinForm({
|
||||
@@ -237,7 +258,9 @@ export default function WatchRoomPage() {
|
||||
</div>
|
||||
<div className="flex-1">
|
||||
<h3 className="text-lg font-bold mb-1">
|
||||
{currentRoom.currentState ? '房主正在播放' : '等待房主开始播放'}
|
||||
{currentRoom.roomType === 'screen'
|
||||
? currentRoom.currentState?.type === 'screen' ? '房主正在共享屏幕' : '等待房主开始共享'
|
||||
: currentRoom.currentState ? '房主正在播放' : '等待房主开始播放'}
|
||||
</h3>
|
||||
<p className="text-sm text-white/80">
|
||||
房间: {currentRoom.name} | 房主: {currentRoom.ownerName}
|
||||
@@ -246,12 +269,14 @@ export default function WatchRoomPage() {
|
||||
<p className="text-xs text-white/90 mt-1">
|
||||
{currentRoom.currentState.type === 'play'
|
||||
? `${currentRoom.currentState.videoName || '未知视频'}`
|
||||
: `${currentRoom.currentState.channelName || '未知频道'}`}
|
||||
: currentRoom.currentState.type === 'live'
|
||||
? `${currentRoom.currentState.channelName || '未知频道'}`
|
||||
: '屏幕共享进行中'}
|
||||
</p>
|
||||
)}
|
||||
{!currentRoom.currentState && (
|
||||
<p className="text-xs text-white/70 mt-1">
|
||||
当房主开始播放时,您将自动跟随
|
||||
{currentRoom.roomType === 'screen' ? '当房主开始共享时,您将自动进入共享页' : '当房主开始播放时,您将自动跟随'}
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
@@ -280,6 +305,8 @@ export default function WatchRoomPage() {
|
||||
// 普通 live 格式,导航到 live 页面
|
||||
router.push(`/live?id=${state.channelId}`);
|
||||
}
|
||||
} else if (state.type === 'screen') {
|
||||
router.push('/watch-room/screen');
|
||||
}
|
||||
}}
|
||||
className="px-6 py-2 bg-white text-blue-600 font-medium rounded-lg hover:bg-white/90 transition-colors whitespace-nowrap"
|
||||
@@ -303,7 +330,7 @@ export default function WatchRoomPage() {
|
||||
)}
|
||||
</h1>
|
||||
<p className="text-sm text-gray-600 dark:text-gray-400 mt-1">
|
||||
与好友一起看视频,实时同步播放
|
||||
与好友一起看视频,支持进度同步或屏幕共享
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -360,7 +387,7 @@ export default function WatchRoomPage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4 mt-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 mt-4">
|
||||
<div className="bg-white/10 backdrop-blur rounded-lg p-3">
|
||||
<p className="text-blue-100 text-xs mb-1">房间号</p>
|
||||
<p className="text-xl font-mono font-bold">{currentRoom.id}</p>
|
||||
@@ -369,6 +396,10 @@ export default function WatchRoomPage() {
|
||||
<p className="text-blue-100 text-xs mb-1">成员数</p>
|
||||
<p className="text-xl font-bold">{members.length} 人</p>
|
||||
</div>
|
||||
<div className="bg-white/10 backdrop-blur rounded-lg p-3">
|
||||
<p className="text-blue-100 text-xs mb-1">房间类型</p>
|
||||
<p className="text-base font-bold">{currentRoom.roomType === 'screen' ? '屏幕共享' : '进度同步'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -402,7 +433,9 @@ export default function WatchRoomPage() {
|
||||
{/* 提示信息 */}
|
||||
<div className="bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4 border border-blue-200 dark:border-blue-800">
|
||||
<p className="text-sm text-blue-800 dark:text-blue-200">
|
||||
💡 前往播放页面或直播页面开始观影,房间成员将自动同步您的操作
|
||||
💡 {currentRoom.roomType === 'screen'
|
||||
? '这是屏幕共享房间,创建后将进入共享页,由房主发起屏幕共享'
|
||||
: '前往播放页面或直播页面开始观影,房间成员将自动同步您的操作'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -471,6 +504,38 @@ export default function WatchRoomPage() {
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<label className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-2">
|
||||
房间类型
|
||||
</label>
|
||||
<div className="grid grid-cols-1 sm:grid-cols-2 gap-3">
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateForm({ ...createForm, roomType: 'sync' })}
|
||||
className={`rounded-lg border p-4 text-left transition-colors ${
|
||||
createForm.roomType === 'sync'
|
||||
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20'
|
||||
: 'border-gray-300 dark:border-gray-600'
|
||||
}`}
|
||||
>
|
||||
<div className="font-medium text-gray-900 dark:text-gray-100">进度同步</div>
|
||||
<div className="mt-1 text-sm text-gray-600 dark:text-gray-400">统一播放进度</div>
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setCreateForm({ ...createForm, roomType: 'screen' })}
|
||||
className={`rounded-lg border p-4 text-left transition-colors ${
|
||||
createForm.roomType === 'screen'
|
||||
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/20'
|
||||
: 'border-gray-300 dark:border-gray-600'
|
||||
}`}
|
||||
>
|
||||
<div className="font-medium text-gray-900 dark:text-gray-100">屏幕共享</div>
|
||||
<div className="mt-1 text-sm text-gray-600 dark:text-gray-400">房员直接观看房主共享的浏览器画面</div>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<button
|
||||
type="submit"
|
||||
disabled={createLoading || !createForm.roomName.trim()}
|
||||
@@ -486,7 +551,7 @@ export default function WatchRoomPage() {
|
||||
{!currentRoom && (
|
||||
<div className="mt-6 bg-blue-50 dark:bg-blue-900/20 rounded-lg p-4 border border-blue-200 dark:border-blue-800">
|
||||
<p className="text-sm text-blue-800 dark:text-blue-200">
|
||||
<strong>提示:</strong>创建房间后,您将成为房主。所有成员的播放进度将自动跟随您的操作。
|
||||
<strong>提示:</strong>创建房间后,您将成为房主。进度同步房会跟随播放状态,屏幕共享房会进入独立共享页。
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -518,7 +583,7 @@ export default function WatchRoomPage() {
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-2 gap-4 mt-4">
|
||||
<div className="grid grid-cols-1 sm:grid-cols-3 gap-4 mt-4">
|
||||
<div className="bg-white/10 backdrop-blur rounded-lg p-3">
|
||||
<p className="text-green-100 text-xs mb-1">房间号</p>
|
||||
<p className="text-xl font-mono font-bold">{currentRoom.id}</p>
|
||||
@@ -527,6 +592,10 @@ export default function WatchRoomPage() {
|
||||
<p className="text-green-100 text-xs mb-1">成员数</p>
|
||||
<p className="text-xl font-bold">{members.length} 人</p>
|
||||
</div>
|
||||
<div className="bg-white/10 backdrop-blur rounded-lg p-3">
|
||||
<p className="text-green-100 text-xs mb-1">房间类型</p>
|
||||
<p className="text-base font-bold">{currentRoom.roomType === 'screen' ? '屏幕共享' : '进度同步'}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -560,7 +629,9 @@ export default function WatchRoomPage() {
|
||||
{/* 提示信息 */}
|
||||
<div className="bg-green-50 dark:bg-green-900/20 rounded-lg p-4 border border-green-200 dark:border-green-800">
|
||||
<p className="text-sm text-green-800 dark:text-green-200">
|
||||
💡 {isOwner ? '前往播放页面或直播页面开始观影,房间成员将自动同步您的操作' : '等待房主开始播放,您的播放进度将自动跟随房主'}
|
||||
💡 {currentRoom.roomType === 'screen'
|
||||
? '这是屏幕共享房间,进入后即可观看房主共享画面'
|
||||
: isOwner ? '前往播放页面或直播页面开始观影,房间成员将自动同步您的操作' : '等待房主开始播放,您的播放进度将自动跟随房主'}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -617,7 +688,7 @@ export default function WatchRoomPage() {
|
||||
{!currentRoom && (
|
||||
<div className="mt-6 bg-green-50 dark:bg-green-900/20 rounded-lg p-4 border border-green-200 dark:border-green-800">
|
||||
<p className="text-sm text-green-800 dark:text-green-200">
|
||||
<strong>提示:</strong>加入房间后,您的播放进度将自动跟随房主的操作。
|
||||
<strong>提示:</strong>加入进度同步房后将跟随播放,加入屏幕共享房后会进入共享页面。
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
@@ -633,7 +704,7 @@ export default function WatchRoomPage() {
|
||||
找到 <span className="font-medium text-gray-900 dark:text-gray-100">{rooms.length}</span> 个公开房间
|
||||
</p>
|
||||
<button
|
||||
onClick={loadRooms}
|
||||
onClick={() => loadRooms(true)}
|
||||
disabled={loading}
|
||||
className="flex items-center gap-2 px-4 py-2 bg-gray-100 dark:bg-gray-700 hover:bg-gray-200 dark:hover:bg-gray-600 rounded-lg text-gray-700 dark:text-gray-300 transition-colors disabled:opacity-50"
|
||||
>
|
||||
@@ -704,6 +775,10 @@ export default function WatchRoomPage() {
|
||||
<span>房主</span>
|
||||
<span className="font-medium">{room.ownerName}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between text-gray-600 dark:text-gray-400">
|
||||
<span>类型</span>
|
||||
<span>{room.roomType === 'screen' ? '屏幕共享' : '进度同步'}</span>
|
||||
</div>
|
||||
<div className="flex items-center justify-between text-gray-600 dark:text-gray-400">
|
||||
<span>创建时间</span>
|
||||
<span>{formatTime(room.createdAt)}</span>
|
||||
@@ -713,7 +788,9 @@ export default function WatchRoomPage() {
|
||||
<p className="text-xs text-blue-700 dark:text-blue-300 truncate">
|
||||
{room.currentState.type === 'play'
|
||||
? `正在播放: ${room.currentState.videoName}`
|
||||
: `正在观看: ${room.currentState.channelName}`}
|
||||
: room.currentState.type === 'live'
|
||||
? `正在观看: ${room.currentState.channelName}`
|
||||
: '正在共享屏幕'}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -0,0 +1,201 @@
|
||||
'use client';
|
||||
|
||||
import { Monitor, MonitorPlay, Users } from 'lucide-react';
|
||||
import Link from 'next/link';
|
||||
import { useRouter } from 'next/navigation';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useWatchRoomContext } from '@/components/WatchRoomProvider';
|
||||
import { useScreenShare } from '@/hooks/useScreenShare';
|
||||
|
||||
const NEW_TAB_KEY_PREFIX = 'watch_room_screen_home_opened_';
|
||||
|
||||
export default function WatchRoomScreenPage() {
|
||||
const router = useRouter();
|
||||
const watchRoom = useWatchRoomContext();
|
||||
const { currentRoom, members, leaveRoom } = watchRoom;
|
||||
const {
|
||||
currentRoom: screenRoom,
|
||||
isOwner,
|
||||
isSharing,
|
||||
isStarting,
|
||||
error,
|
||||
localVideoRef,
|
||||
remoteVideoRef,
|
||||
startSharing,
|
||||
stopSharing,
|
||||
} = useScreenShare();
|
||||
|
||||
useEffect(() => {
|
||||
if (!currentRoom) {
|
||||
router.replace('/watch-room');
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentRoom.roomType !== 'screen') {
|
||||
router.replace('/watch-room');
|
||||
}
|
||||
}, [currentRoom, router]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!screenRoom || !isOwner) return;
|
||||
|
||||
const key = `${NEW_TAB_KEY_PREFIX}${screenRoom.id}`;
|
||||
if (sessionStorage.getItem(key)) return;
|
||||
|
||||
sessionStorage.setItem(key, '1');
|
||||
window.open('/?watchRoomNoConnect=1', '_blank', 'noopener,noreferrer');
|
||||
}, [isOwner, screenRoom?.id]);
|
||||
|
||||
if (!screenRoom || screenRoom.roomType !== 'screen') {
|
||||
return null;
|
||||
}
|
||||
|
||||
const handleLeave = () => {
|
||||
if (isOwner && isSharing) {
|
||||
stopSharing(true);
|
||||
}
|
||||
leaveRoom();
|
||||
router.push('/watch-room');
|
||||
};
|
||||
|
||||
return (
|
||||
<div className='min-h-screen bg-white text-gray-900 dark:bg-black dark:text-gray-200'>
|
||||
<div className='mx-auto flex min-h-screen max-w-7xl flex-col gap-4 px-4 py-4 lg:px-8'>
|
||||
<div className='flex items-center justify-between gap-4 rounded-2xl border border-gray-200 bg-white/90 px-5 py-4 shadow-sm dark:border-gray-800 dark:bg-gray-900/80'>
|
||||
<div>
|
||||
<h1 className='flex items-center gap-2 text-2xl font-semibold'>
|
||||
<Monitor className='h-6 w-6 text-blue-500' />
|
||||
屏幕共享观影室
|
||||
</h1>
|
||||
<p className='mt-1 text-sm text-gray-600 dark:text-gray-400'>
|
||||
房间:{screenRoom.name} · 房主:{screenRoom.ownerName}
|
||||
</p>
|
||||
</div>
|
||||
<div className='flex items-center gap-2'>
|
||||
{isOwner && (
|
||||
<Link
|
||||
href='/?watchRoomNoConnect=1'
|
||||
target='_blank'
|
||||
rel='noreferrer'
|
||||
className='rounded-lg bg-blue-500 px-4 py-2 text-white'
|
||||
>
|
||||
新开主页
|
||||
</Link>
|
||||
)}
|
||||
<button
|
||||
onClick={handleLeave}
|
||||
className='rounded-lg bg-gray-200 px-4 py-2 text-gray-900 dark:bg-gray-700 dark:text-gray-100'
|
||||
>
|
||||
离开房间
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='grid flex-1 grid-cols-1 gap-4 xl:grid-cols-[1fr_320px]'>
|
||||
<div className='relative flex min-h-[420px] items-center justify-center overflow-hidden rounded-2xl border border-gray-200 bg-black dark:border-gray-800'>
|
||||
{isOwner ? (
|
||||
<video
|
||||
ref={localVideoRef}
|
||||
autoPlay
|
||||
muted
|
||||
playsInline
|
||||
className='h-full w-full bg-black object-contain'
|
||||
/>
|
||||
) : (
|
||||
<video
|
||||
ref={remoteVideoRef}
|
||||
autoPlay
|
||||
playsInline
|
||||
controls
|
||||
className='h-full w-full bg-black object-contain'
|
||||
/>
|
||||
)}
|
||||
|
||||
{!isSharing && (
|
||||
<div className='absolute px-6 text-center text-white'>
|
||||
<MonitorPlay className='mx-auto mb-3 h-12 w-12 text-white/70' />
|
||||
<p className='text-lg font-medium'>
|
||||
{isOwner ? '点击开始共享,向房员推送浏览器画面' : '等待房主开始共享屏幕'}
|
||||
</p>
|
||||
{isOwner && (
|
||||
<p className='mt-2 text-sm text-white/70'>
|
||||
本页不要关闭;已尝试为你新开一个主页标签页方便继续浏览。
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='space-y-4'>
|
||||
<div className='rounded-xl border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900'>
|
||||
<h2 className='mb-3 font-semibold'>共享状态</h2>
|
||||
<div className='space-y-2 text-sm text-gray-600 dark:text-gray-400'>
|
||||
<p>类型:屏幕共享</p>
|
||||
<p>状态:{isSharing ? '共享中' : '未开始'}</p>
|
||||
<p>成员:{members.length} 人</p>
|
||||
</div>
|
||||
|
||||
{error && (
|
||||
<div className='mt-3 rounded-lg border border-red-200 bg-red-50 px-3 py-2 text-sm text-red-700 dark:border-red-800 dark:bg-red-900/20 dark:text-red-300'>
|
||||
{error}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className='mt-4 flex gap-3'>
|
||||
{isOwner ? (
|
||||
<>
|
||||
<button
|
||||
onClick={() => startSharing()}
|
||||
disabled={isStarting || isSharing}
|
||||
className='flex-1 rounded-lg bg-blue-500 px-4 py-2 text-white disabled:bg-gray-400'
|
||||
>
|
||||
{isStarting ? '启动中...' : isSharing ? '共享中' : '开始共享'}
|
||||
</button>
|
||||
<button
|
||||
onClick={() => stopSharing(true)}
|
||||
disabled={!isSharing}
|
||||
className='rounded-lg bg-red-500 px-4 py-2 text-white disabled:bg-gray-400'
|
||||
>
|
||||
停止
|
||||
</button>
|
||||
</>
|
||||
) : (
|
||||
<div className='rounded-lg bg-blue-50 px-3 py-2 text-sm text-blue-700 dark:bg-blue-900/20 dark:text-blue-300'>
|
||||
房员无需操作,房主开始共享后会自动显示画面。
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='rounded-xl border border-gray-200 bg-white p-4 dark:border-gray-800 dark:bg-gray-900'>
|
||||
<h2 className='mb-3 flex items-center gap-2 font-semibold'>
|
||||
<Users className='h-4 w-4' />
|
||||
房间成员
|
||||
</h2>
|
||||
<div className='space-y-2'>
|
||||
{members.map((member) => (
|
||||
<div
|
||||
key={member.id}
|
||||
className='flex items-center justify-between rounded-lg bg-gray-50 px-3 py-2 dark:bg-gray-800/70'
|
||||
>
|
||||
<span className='text-sm'>{member.name}</span>
|
||||
{member.isOwner && (
|
||||
<span className='rounded bg-yellow-100 px-2 py-1 text-xs text-yellow-800 dark:bg-yellow-900/20 dark:text-yellow-300'>
|
||||
房主
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='rounded-xl border border-blue-200 bg-blue-50 p-4 text-sm text-blue-800 dark:border-blue-800 dark:bg-blue-900/20 dark:text-blue-200'>
|
||||
本页不再包裹站点导航,便于直接共享。建议使用桌面版 Chrome / Edge,并优先共享标签页。
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user