feat(frontend): load guild-channel lists and sync chat channel in url
This commit is contained in:
@@ -1,4 +1,5 @@
|
|||||||
import { useEffect, useMemo, useState } from 'react'
|
import { useEffect, useMemo, useState } from 'react'
|
||||||
|
import { useSearchParams } from 'react-router-dom'
|
||||||
import { getApiClient } from '../lib/api-client'
|
import { getApiClient } from '../lib/api-client'
|
||||||
import { disconnectSocket, getSocketClient } from '../lib/socket-client'
|
import { disconnectSocket, getSocketClient } from '../lib/socket-client'
|
||||||
|
|
||||||
@@ -10,7 +11,9 @@ type MessageItem = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default function ChatPage() {
|
export default function ChatPage() {
|
||||||
const [channelId, setChannelId] = useState('')
|
const [searchParams, setSearchParams] = useSearchParams()
|
||||||
|
const guildId = searchParams.get('guildId') ?? ''
|
||||||
|
const [channelId, setChannelId] = useState(() => searchParams.get('channelId') ?? '')
|
||||||
const [content, setContent] = useState('')
|
const [content, setContent] = useState('')
|
||||||
const [messages, setMessages] = useState<MessageItem[]>([])
|
const [messages, setMessages] = useState<MessageItem[]>([])
|
||||||
const [socketState, setSocketState] = useState<'offline' | 'online'>('offline')
|
const [socketState, setSocketState] = useState<'offline' | 'online'>('offline')
|
||||||
@@ -54,6 +57,15 @@ export default function ChatPage() {
|
|||||||
setContent('')
|
setContent('')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function onChangeChannel(value: string) {
|
||||||
|
setChannelId(value)
|
||||||
|
const next = new URLSearchParams(searchParams)
|
||||||
|
if (guildId) next.set('guildId', guildId)
|
||||||
|
if (value) next.set('channelId', value)
|
||||||
|
else next.delete('channelId')
|
||||||
|
setSearchParams(next)
|
||||||
|
}
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (!channelId || !socket.connected) return
|
if (!channelId || !socket.connected) return
|
||||||
socket.emit('join_channel', { channelId })
|
socket.emit('join_channel', { channelId })
|
||||||
@@ -65,9 +77,10 @@ export default function ChatPage() {
|
|||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<h2>聊天</h2>
|
<h2>聊天</h2>
|
||||||
|
<p>Guild: {guildId || '-'}</p>
|
||||||
<p>Socket: {socketState}</p>
|
<p>Socket: {socketState}</p>
|
||||||
<div style={{ display: 'flex', gap: 8, marginBottom: 8 }}>
|
<div style={{ display: 'flex', gap: 8, marginBottom: 8 }}>
|
||||||
<input value={channelId} onChange={(e) => setChannelId(e.target.value)} placeholder="Channel ID" />
|
<input value={channelId} onChange={(e) => onChangeChannel(e.target.value)} placeholder="Channel ID" />
|
||||||
<button onClick={pullMessages}>拉取</button>
|
<button onClick={pullMessages}>拉取</button>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: 'flex', gap: 8, marginBottom: 8 }}>
|
<div style={{ display: 'flex', gap: 8, marginBottom: 8 }}>
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import type { FormEvent } from 'react'
|
import type { FormEvent } from 'react'
|
||||||
|
import { Link } from 'react-router-dom'
|
||||||
import { getApiClient, resetApiClient } from '../lib/api-client'
|
import { getApiClient, resetApiClient } from '../lib/api-client'
|
||||||
import {
|
import {
|
||||||
getRuntimeConfig,
|
getRuntimeConfig,
|
||||||
@@ -11,6 +12,8 @@ import { reconnectSocket } from '../lib/socket-client'
|
|||||||
export default function WorkspacePage() {
|
export default function WorkspacePage() {
|
||||||
const [form, setForm] = useState<RuntimeConfig>(getRuntimeConfig())
|
const [form, setForm] = useState<RuntimeConfig>(getRuntimeConfig())
|
||||||
const [health, setHealth] = useState('')
|
const [health, setHealth] = useState('')
|
||||||
|
const [guilds, setGuilds] = useState<Array<{ id: string; name: string; slug: string }>>([])
|
||||||
|
const [channelsByGuild, setChannelsByGuild] = useState<Record<string, Array<{ id: string; name: string }>>>({})
|
||||||
|
|
||||||
async function onSave(e: FormEvent) {
|
async function onSave(e: FormEvent) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@@ -29,6 +32,26 @@ export default function WorkspacePage() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function loadGuilds() {
|
||||||
|
try {
|
||||||
|
const res = await getApiClient().get('/guilds')
|
||||||
|
const list = Array.isArray(res.data) ? res.data : []
|
||||||
|
setGuilds(list)
|
||||||
|
} catch {
|
||||||
|
setGuilds([])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadChannels(guildId: string) {
|
||||||
|
try {
|
||||||
|
const res = await getApiClient().get('/channels', { params: { guildId } })
|
||||||
|
const list = Array.isArray(res.data) ? res.data : []
|
||||||
|
setChannelsByGuild((prev) => ({ ...prev, [guildId]: list }))
|
||||||
|
} catch {
|
||||||
|
setChannelsByGuild((prev) => ({ ...prev, [guildId]: [] }))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section>
|
<section>
|
||||||
<h2>工作台</h2>
|
<h2>工作台</h2>
|
||||||
@@ -61,6 +84,31 @@ export default function WorkspacePage() {
|
|||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<p>{health}</p>
|
<p>{health}</p>
|
||||||
|
<div style={{ marginTop: 12 }}>
|
||||||
|
<button type="button" onClick={loadGuilds}>
|
||||||
|
加载 Guild 列表
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
{guilds.map((g) => (
|
||||||
|
<li key={g.id} style={{ marginTop: 8 }}>
|
||||||
|
<strong>{g.name}</strong> ({g.slug}){' '}
|
||||||
|
<button type="button" onClick={() => loadChannels(g.id)}>
|
||||||
|
加载频道
|
||||||
|
</button>
|
||||||
|
<ul>
|
||||||
|
{(channelsByGuild[g.id] ?? []).map((c) => (
|
||||||
|
<li key={c.id}>
|
||||||
|
<Link to={`/chat?guildId=${encodeURIComponent(g.id)}&channelId=${encodeURIComponent(c.id)}`}>
|
||||||
|
#{c.name}
|
||||||
|
</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
|
</ul>
|
||||||
</section>
|
</section>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user