Files
WebDrop/web/src/features/channel/InviteSheet.tsx
T

45 lines
2.0 KiB
TypeScript

import { useState, type FormEvent } from 'react';
import { errorMessage } from '@/core-bridge/errors';
import { useToast } from '@/store/toast';
import { useWorkspace } from '@/store/workspace';
import { Button } from '@/ui/Button';
import { Sheet } from '@/ui/Sheet';
import styles from './MembersPane.module.css';
export function InviteSheet({ onClose, onInvited }: { onClose: () => void; onInvited: () => void }) {
const invite = useWorkspace((s) => s.inviteUser);
const [username, setUsername] = useState('');
const [busy, setBusy] = useState(false);
const [error, setError] = useState('');
async function submit(event: FormEvent) {
event.preventDefault();
const target = username.trim();
if (!target || busy) return;
setBusy(true); setError('');
try {
await invite(target);
useToast.getState().push({ kind: 'ok', text: `已向 ${target} 发送邀请` });
onInvited(); onClose();
} catch (cause) {
const message = errorMessage(cause);
setError(message);
useToast.getState().push({ kind: 'error', text: `邀请失败:${message}` });
} finally { setBusy(false); }
}
return <Sheet title="邀请成员" onClose={() => { if (!busy) onClose(); }} placement="top">
<form className={styles.invite} onSubmit={(event) => { void submit(event); }}>
<label>账号 ID
<input autoFocus maxLength={32} value={username} disabled={busy} placeholder="已注册用户的账号 ID" onChange={(event) => setUsername(event.target.value)} />
</label>
<p className={styles.note}>对方登录后会收到通知,接受邀请后加入空间。能否读取加入前的历史,取决于各频道的历史开关。</p>
{error ? <p className={styles.error} role="alert">{error}</p> : null}
<div className={styles.inviteActions}>
<Button variant="ghost" disabled={busy} onClick={onClose}>取消</Button>
<Button type="submit" variant="primary" disabled={busy || !username.trim()}>{busy ? '发送中…' : '发送邀请'}</Button>
</div>
</form>
</Sheet>;
}