|
|
|
|
@ -8,18 +8,20 @@ import { ClientMessage, RoomStateChangedMessage, ServerMessage, UserJoinLeaveMes
|
|
|
|
|
import { $playerState, $userInfo, $userStatus } from '@/store/player'
|
|
|
|
|
import { useStore } from '@nanostores/react'
|
|
|
|
|
import { useRouter } from 'next/router'
|
|
|
|
|
import { useCallback, useEffect, useState } from 'react'
|
|
|
|
|
import { useCallback, useEffect, useMemo, useState } from 'react'
|
|
|
|
|
import "@radix-ui/themes/components/tabs"
|
|
|
|
|
import { Label } from '@/components/ui/label'
|
|
|
|
|
import { useSignal } from '@/lib/signal'
|
|
|
|
|
import Head from 'next/head'
|
|
|
|
|
|
|
|
|
|
export default function Page() {
|
|
|
|
|
const router = useRouter()
|
|
|
|
|
const userInfo = useStore($userInfo)
|
|
|
|
|
const playerState = useStore($playerState)
|
|
|
|
|
const [joinRole, setJoinRole] = useState<string>('user')
|
|
|
|
|
const [urlInput, setUrlInput] = useState<string | undefined>()
|
|
|
|
|
const [isRoomEmpty, setIsRoomEmpty] = useState(false)
|
|
|
|
|
const [isJoined, setIsJoined] = useState(false)
|
|
|
|
|
|
|
|
|
|
const joinRole = useSignal<string>('user')
|
|
|
|
|
const urlInput = useSignal<string | undefined>()
|
|
|
|
|
const isRoomEmpty = useSignal(false)
|
|
|
|
|
const isJoined = useSignal(false)
|
|
|
|
|
|
|
|
|
|
const roomName = router.query.room as string
|
|
|
|
|
|
|
|
|
|
@ -34,12 +36,12 @@ export default function Page() {
|
|
|
|
|
function onRoomInfo(d: any) {
|
|
|
|
|
const msg = d as RoomStateChangedMessage
|
|
|
|
|
if (!msg.userStatus || msg.userStatus.length === 0) {
|
|
|
|
|
setIsRoomEmpty(true)
|
|
|
|
|
setJoinRole('admin')
|
|
|
|
|
isRoomEmpty.value = true
|
|
|
|
|
joinRole.value = 'admin'
|
|
|
|
|
return
|
|
|
|
|
} else {
|
|
|
|
|
setIsRoomEmpty(false)
|
|
|
|
|
setJoinRole('user')
|
|
|
|
|
isRoomEmpty.value = false
|
|
|
|
|
joinRole.value = 'user'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$userStatus.set([
|
|
|
|
|
@ -53,7 +55,7 @@ export default function Page() {
|
|
|
|
|
if (!msg.userInfo) {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
setIsJoined(true)
|
|
|
|
|
isJoined.value = true
|
|
|
|
|
$userInfo.set({
|
|
|
|
|
...$userInfo.value,
|
|
|
|
|
isAdmin: msg.userInfo.isAdmin,
|
|
|
|
|
@ -62,6 +64,10 @@ export default function Page() {
|
|
|
|
|
console.log('$userInfo', $userInfo.value)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function onSetUrl(d: any) {
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
socket.on('connect', onConnect)
|
|
|
|
|
socket.on('roomInfo', onRoomInfo)
|
|
|
|
|
socket.on('joined', onJoined)
|
|
|
|
|
@ -80,35 +86,38 @@ export default function Page() {
|
|
|
|
|
const handleJoinClick = useCallback(() => {
|
|
|
|
|
socket.connect()
|
|
|
|
|
socket.emit('join', {
|
|
|
|
|
username: userInfo?.username,
|
|
|
|
|
username: $userInfo.value?.username,
|
|
|
|
|
room: roomName,
|
|
|
|
|
password: userInfo?.password,
|
|
|
|
|
password: $userInfo.value?.password,
|
|
|
|
|
} as ClientMessage)
|
|
|
|
|
}, [userInfo, roomName])
|
|
|
|
|
}, [roomName])
|
|
|
|
|
|
|
|
|
|
const handleSetUrlClick = useCallback(() => {
|
|
|
|
|
$playerState.set({ ...$playerState.value, url: urlInput })
|
|
|
|
|
$playerState.set({ ...$playerState.value, url: urlInput.value })
|
|
|
|
|
socket.emit('setUrl', {
|
|
|
|
|
room: roomName,
|
|
|
|
|
username: userInfo?.username,
|
|
|
|
|
url: urlInput
|
|
|
|
|
username: $userInfo.value?.username,
|
|
|
|
|
url: urlInput.value,
|
|
|
|
|
} as ClientMessage)
|
|
|
|
|
}, [roomName, userInfo, urlInput])
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
const isAllowedLogin = useCallback(() => {
|
|
|
|
|
if (isJoined) {
|
|
|
|
|
if (isJoined.value) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (joinRole === 'admin' && !userInfo?.password) {
|
|
|
|
|
if (joinRole.value === 'admin' && !$userInfo.value?.password) {
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
return userInfo?.username && userInfo.username.length > 0
|
|
|
|
|
}, [joinRole, isJoined, userInfo])
|
|
|
|
|
return $userInfo.value?.username && $userInfo.value.username.length > 0
|
|
|
|
|
}, [])
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
<div className='flex flex-col lg:flex-row m-2 justify-center'>
|
|
|
|
|
{isJoined && <div className='w-full lg:mr-2'>
|
|
|
|
|
<Head>
|
|
|
|
|
<title>「{roomName}」的房间 | 一起看</title>
|
|
|
|
|
</Head>
|
|
|
|
|
{isJoined.value && <div className='w-full lg:mr-2'>
|
|
|
|
|
<Player roomName={roomName} />
|
|
|
|
|
</div>}
|
|
|
|
|
<div className='w-full lg:w-[450px] mb-1 border rounded'>
|
|
|
|
|
@ -117,12 +126,12 @@ export default function Page() {
|
|
|
|
|
|
|
|
|
|
<div className='flex flex-row gap-4 items-center'>
|
|
|
|
|
<Badge className='!px-2 !py-1 mt-1'>加入身份</Badge>
|
|
|
|
|
<Tabs.Root value={joinRole} onValueChange={setJoinRole}>
|
|
|
|
|
<Tabs.Root value={joinRole.value} onValueChange={joinRole.setValue}>
|
|
|
|
|
<Tabs.List size="1">
|
|
|
|
|
<Tabs.Trigger
|
|
|
|
|
value="user"
|
|
|
|
|
disabled={isRoomEmpty}
|
|
|
|
|
title={isRoomEmpty ? '创建房间必须使用房管身份' : undefined}>
|
|
|
|
|
disabled={isRoomEmpty.value}
|
|
|
|
|
title={isRoomEmpty.value ? '创建房间必须使用房管身份' : undefined}>
|
|
|
|
|
观众
|
|
|
|
|
</Tabs.Trigger>
|
|
|
|
|
<Tabs.Trigger value="admin">房管</Tabs.Trigger>
|
|
|
|
|
@ -132,51 +141,51 @@ export default function Page() {
|
|
|
|
|
</div>
|
|
|
|
|
{roomName && <div className='m-2 flex flex-row gap-2'>
|
|
|
|
|
<Input
|
|
|
|
|
value={userInfo?.username ?? ""}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
$userInfo.set({
|
|
|
|
|
...userInfo,
|
|
|
|
|
...$userInfo.value,
|
|
|
|
|
username: e.target.value
|
|
|
|
|
})
|
|
|
|
|
}}
|
|
|
|
|
value={userInfo?.username ?? ""}
|
|
|
|
|
placeholder='你的用户名'
|
|
|
|
|
name='username'
|
|
|
|
|
disabled={isJoined}
|
|
|
|
|
disabled={isJoined.value}
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
{joinRole == 'admin' && (
|
|
|
|
|
{joinRole.value == 'admin' && (
|
|
|
|
|
<Input
|
|
|
|
|
placeholder='管理密码'
|
|
|
|
|
value={userInfo?.password ?? ""}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
$userInfo.set({
|
|
|
|
|
...userInfo,
|
|
|
|
|
...$userInfo.value,
|
|
|
|
|
password: e.target.value,
|
|
|
|
|
})
|
|
|
|
|
}}
|
|
|
|
|
value={userInfo?.password ?? ""}
|
|
|
|
|
type='password'
|
|
|
|
|
name='password'
|
|
|
|
|
disabled={isJoined}
|
|
|
|
|
disabled={isJoined.value}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
<Button
|
|
|
|
|
onClick={handleJoinClick}
|
|
|
|
|
disabled={!isAllowedLogin()}
|
|
|
|
|
>{isRoomEmpty ? "创建房间" : "加入房间"}</Button>
|
|
|
|
|
>{isRoomEmpty.value ? "创建房间" : "加入房间"}</Button>
|
|
|
|
|
</div>}
|
|
|
|
|
{isJoined && userInfo?.isAdmin && <div className='m-2 flex flex-row gap-2'>
|
|
|
|
|
{isJoined.value && userInfo?.isAdmin && <div className='m-2 flex flex-row gap-2'>
|
|
|
|
|
<Input
|
|
|
|
|
name='videoUrl'
|
|
|
|
|
type='url'
|
|
|
|
|
value={urlInput}
|
|
|
|
|
autoComplete='url'
|
|
|
|
|
value={urlInput.value}
|
|
|
|
|
onChange={(e) => {
|
|
|
|
|
setUrlInput(e.target.value)
|
|
|
|
|
urlInput.value = e.target.value
|
|
|
|
|
}}
|
|
|
|
|
autoComplete='url'
|
|
|
|
|
placeholder='视频直链'
|
|
|
|
|
/>
|
|
|
|
|
<Button onClick={handleSetUrlClick} >修改链接</Button>
|
|
|
|
|
<Button onClick={handleSetUrlClick}>修改链接</Button>
|
|
|
|
|
</div>}
|
|
|
|
|
{roomName && <UserList roomName={roomName} />}
|
|
|
|
|
</div>
|
|
|
|
|
|