Add read-only chatroom
This commit is contained in:
174
src/app/game/berry-dash/chatroom/page.tsx
Normal file
174
src/app/game/berry-dash/chatroom/page.tsx
Normal file
@@ -0,0 +1,174 @@
|
||||
'use client'
|
||||
|
||||
import { BackButton } from '@/app/components/BackButton'
|
||||
import { DiscordButton } from '@/app/components/DiscordButton'
|
||||
import { GetIconForUser } from '@/util/bd'
|
||||
import axios from 'axios'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
|
||||
interface WSMessage {
|
||||
success: boolean
|
||||
message: string | null
|
||||
for: string
|
||||
data: any
|
||||
}
|
||||
|
||||
type BirdColor = [number, number, number]
|
||||
|
||||
interface Message {
|
||||
username: string
|
||||
userId: number
|
||||
content: string
|
||||
id: number
|
||||
icon: number
|
||||
overlay: number
|
||||
birdColor: BirdColor
|
||||
overlayColor: BirdColor
|
||||
customIcon: string | null
|
||||
}
|
||||
|
||||
interface CustomIconEntry {
|
||||
data: string
|
||||
id: string
|
||||
}
|
||||
|
||||
export default function BerryDashChatroom () {
|
||||
const [connected, setConnected] = useState<boolean>(false)
|
||||
const [messages, setMessages] = useState<Message[]>([])
|
||||
const [customIconCache, setCustomIconCache] = useState<CustomIconEntry[]>([])
|
||||
const [ws, setWs] = useState<WebSocket | null>(null)
|
||||
const messagesDiv = useRef<HTMLDivElement>(null)
|
||||
|
||||
useEffect(() => {
|
||||
document.title = 'Lncvrt Games - Chatroom'
|
||||
|
||||
const socket = new WebSocket('wss://games.lncvrt.xyz/api/ws')
|
||||
|
||||
socket.onopen = () => {
|
||||
setConnected(true)
|
||||
socket.send(
|
||||
JSON.stringify({
|
||||
type: 'info_request',
|
||||
kind: 'chatroom_messages',
|
||||
timestamp: Date.now()
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
socket.onmessage = event => {
|
||||
const message = JSON.parse(event.data) as WSMessage
|
||||
if (message.for == 'info_request:chatroom_messages') {
|
||||
const messages = message.data as Message[]
|
||||
setMessages(messages)
|
||||
} else if (message.for == 'upload:chatroom_message') {
|
||||
const msg = message.data as Message
|
||||
setMessages(prev => [...prev.slice(1), msg])
|
||||
}
|
||||
}
|
||||
|
||||
socket.onclose = () => {
|
||||
setConnected(false)
|
||||
setMessages([])
|
||||
}
|
||||
|
||||
setWs(socket)
|
||||
|
||||
return () => {
|
||||
socket.close()
|
||||
}
|
||||
}, [])
|
||||
|
||||
useEffect(() => {
|
||||
if (messagesDiv.current) {
|
||||
messagesDiv.current.scrollTop = messagesDiv.current.scrollHeight
|
||||
}
|
||||
const all = customIconCache.map(icon => icon.id)
|
||||
const allFromMessages = Array.from(
|
||||
new Set(
|
||||
messages
|
||||
.filter(icon => icon.customIcon != null)
|
||||
.map(icon => icon.customIcon as string)
|
||||
)
|
||||
)
|
||||
const notInAllIds = allFromMessages
|
||||
.filter(id => !all.includes(id))
|
||||
.map(id => `"${id}"`)
|
||||
.join(',')
|
||||
|
||||
;(async () => {
|
||||
const result = await axios.get(
|
||||
`https://games.lncvrt.xyz/api/berrydash/icon-marketplace/icon?ids=[${notInAllIds}]`
|
||||
)
|
||||
if (result.data.success) {
|
||||
const add: CustomIconEntry[] = []
|
||||
for (const item of result.data.data) {
|
||||
add.push({
|
||||
data: item.data,
|
||||
id: item.id
|
||||
})
|
||||
}
|
||||
setCustomIconCache(prev => [
|
||||
...prev,
|
||||
...result.data.data.map((item: CustomIconEntry) => ({
|
||||
data: item.data,
|
||||
id: item.id
|
||||
}))
|
||||
])
|
||||
}
|
||||
})()
|
||||
}, [messages])
|
||||
|
||||
return (
|
||||
<div className='box'>
|
||||
<BackButton href='/game/berry-dash' />
|
||||
<DiscordButton />
|
||||
<p className='px-8 mb-4 -mt-2 text-center text-2xl'>
|
||||
Berry Dash Chatroom
|
||||
</p>
|
||||
{connected && (
|
||||
<>
|
||||
<div
|
||||
className='sub-box -m-4 mt-0 flex flex-col gap-2 max-h-[calc(100vh-204px)] overflow-y-auto'
|
||||
ref={messagesDiv}
|
||||
>
|
||||
{messages.map(item => {
|
||||
return (
|
||||
<div key={item.id} className='sub-box2 flex flex-row gap-1'>
|
||||
<img
|
||||
src={
|
||||
!item.customIcon
|
||||
? `https://games-r2.lncvrt.xyz/game-assets/berrydash/icons/bird_${
|
||||
item.icon == 1
|
||||
? GetIconForUser(item.userId)
|
||||
: item.icon
|
||||
}.png`
|
||||
: customIconCache.find(i => i.id === item.customIcon)
|
||||
? 'data:image/png;base64,' +
|
||||
customIconCache.find(i => i.id === item.customIcon)
|
||||
?.data
|
||||
: 'https://games-r2.lncvrt.xyz/game-assets/berrydash/other/loading.png'
|
||||
}
|
||||
className='pointer-events-none'
|
||||
width={48}
|
||||
height={48}
|
||||
></img>
|
||||
<div>
|
||||
<p>{item.username}</p>
|
||||
<p className='max-w-240 truncate select-text'>
|
||||
{atob(item.content)}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
})}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
{!connected && (
|
||||
<p className='text-center text-red-500'>
|
||||
Not connected to the chatroom
|
||||
</p>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user