Compare commits

...

1 Commits

Author SHA1 Message Date
nav
25bd1df290 feat(frontend): add loading empty and error states for chat operations 2026-05-12 16:08:17 +00:00

View File

@@ -26,6 +26,8 @@ export default function ChatPage() {
const [socketState, setSocketState] = useState<'offline' | 'online'>('offline')
const [onlineCount, setOnlineCount] = useState(0)
const [typingUsers, setTypingUsers] = useState<string[]>([])
const [loading, setLoading] = useState(false)
const [error, setError] = useState('')
const [seqFrom, setSeqFrom] = useState('1')
const [seqTo, setSeqTo] = useState('999999')
const [limit, setLimit] = useState('50')
@@ -86,40 +88,63 @@ export default function ChatPage() {
async function pullMessages() {
if (!channelId) return
const res = await getApiClient().get(`/channels/${channelId}/messages`, {
params: {
seq_from: Number(seqFrom || '1'),
seq_to: Number(seqTo || '999999'),
limit: Number(limit || '50'),
},
})
setMessages(res.data.items ?? [])
setPageInfo(res.data.page ?? null)
setLoading(true)
setError('')
try {
const res = await getApiClient().get(`/channels/${channelId}/messages`, {
params: {
seq_from: Number(seqFrom || '1'),
seq_to: Number(seqTo || '999999'),
limit: Number(limit || '50'),
},
})
setMessages(res.data.items ?? [])
setPageInfo(res.data.page ?? null)
} catch {
setError('消息拉取失败')
} finally {
setLoading(false)
}
}
async function sendMessage() {
if (!channelId || !content.trim()) return
await getApiClient().post(`/channels/${channelId}/messages`, {
content,
authorUserId: 'frontend-user',
})
socket.emit('typing.stop', { channelId })
setContent('')
setError('')
try {
await getApiClient().post(`/channels/${channelId}/messages`, {
content,
authorUserId: 'frontend-user',
})
socket.emit('typing.stop', { channelId })
setContent('')
} catch {
setError('发送失败')
}
}
async function editMessage() {
if (!channelId || !editingMessageId || !editingContent.trim()) return
await getApiClient().patch(`/channels/${channelId}/messages/${editingMessageId}`, {
content: editingContent,
})
setEditingContent('')
await pullMessages()
setError('')
try {
await getApiClient().patch(`/channels/${channelId}/messages/${editingMessageId}`, {
content: editingContent,
})
setEditingContent('')
await pullMessages()
} catch {
setError('编辑失败')
}
}
async function deleteMessage(messageId: string) {
if (!channelId || !messageId) return
await getApiClient().delete(`/channels/${channelId}/messages/${messageId}`)
await pullMessages()
setError('')
try {
await getApiClient().delete(`/channels/${channelId}/messages/${messageId}`)
await pullMessages()
} catch {
setError('删除失败')
}
}
function onChangeChannel(value: string) {
@@ -155,6 +180,8 @@ export default function ChatPage() {
<p>Guild: {guildId || '-'}</p>
<p>Socket: {socketState}</p>
<p>线: {onlineCount}</p>
{loading ? <p>...</p> : null}
{error ? <p style={{ color: 'crimson' }}>{error}</p> : null}
{typingUsers.length ? <p>: {typingUsers.join(', ')}</p> : null}
<div style={{ display: 'flex', gap: 8, marginBottom: 8 }}>
<input value={channelId} onChange={(e) => onChangeChannel(e.target.value)} placeholder="Channel ID" />
@@ -186,6 +213,7 @@ export default function ChatPage() {
</li>
))}
</ul>
{!loading && !messages.length ? <p></p> : null}
{pageInfo ? (
<p>
next_expected_seq: {pageInfo.nextExpectedSeq ?? '-'} | highest_committed_seq:{' '}