26 lines
1.6 KiB
TypeScript
26 lines
1.6 KiB
TypeScript
import { useEffect, useState } from 'react';
|
|
import { accountApi, type AccountInvitation } from '@/core-bridge/account';
|
|
import { useChannels } from '@/store/channels';
|
|
import { Button } from '@/ui/Button';
|
|
import { channelPath, navigate } from '@/app/navigation';
|
|
import styles from './AccountPanel.module.css';
|
|
export function InvitationInbox() {
|
|
const [invitations, setInvitations] = useState<AccountInvitation[]>([]);
|
|
const [error, setError] = useState('');
|
|
const [busy, setBusy] = useState<string>();
|
|
useEffect(() => { void accountApi.invitations().then(setInvitations).catch(() => setError('读取邀请失败')); }, []);
|
|
async function accept(id: string) {
|
|
setBusy(id); setError('');
|
|
try { await accountApi.acceptInvitation(id); await useChannels.getState().refresh(); navigate(channelPath(id)); }
|
|
catch (cause) { setError(cause instanceof Error ? cause.message : '加入失败'); }
|
|
finally { setBusy(undefined); }
|
|
}
|
|
return <div><strong>空间邀请</strong>
|
|
<Button variant="ghost" disabled={Boolean(busy)} onClick={() => { void accountApi.invitations().then(setInvitations).catch(() => setError('读取邀请失败')); }}>刷新邀请</Button>
|
|
{invitations.length === 0 ? <p className={styles.note}>暂无邀请。</p> : invitations.map((row) => <div className={styles.actions} key={row.channel_id}>
|
|
<span>空间 {row.channel_id.slice(0, 8)}…</span><Button disabled={Boolean(busy)} onClick={() => { void accept(row.channel_id); }}>{busy === row.channel_id ? '加入中…' : '接受邀请'}</Button>
|
|
</div>)}
|
|
{error ? <p className={styles.error} role="alert">{error}</p> : null}
|
|
</div>;
|
|
}
|