feat(web): add spaces, grouped channels and file chat
This commit is contained in:
1 parent
c7d8ef15bc
commit
f6cfb12716
111 files changed
+4371
-506
No files matched your search
@@ -0,0 +1,38 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
import { accountApi, type AccountDevice } from '@/core-bridge/account';
|
||||
import { useAccount } from '@/store/account';
|
||||
import { Button } from '@/ui/Button';
|
||||
import styles from './AccountPanel.module.css';
|
||||
|
||||
export function AccountDevices() {
|
||||
const [devices, setDevices] = useState<AccountDevice[]>([]);
|
||||
const [names, setNames] = useState<Record<string, string>>({});
|
||||
const [error, setError] = useState('');
|
||||
const [busy, setBusy] = useState(false);
|
||||
const refreshAccount = useAccount((s) => s.refresh);
|
||||
async function refresh() { setDevices(await accountApi.devices()); }
|
||||
useEffect(() => { void refresh().catch(() => setError('设备清单读取失败')); }, []);
|
||||
async function change(device: AccountDevice, revoke: boolean) {
|
||||
setBusy(true); setError('');
|
||||
try {
|
||||
if (revoke) {
|
||||
await accountApi.revokeDevice(device.id); await refreshAccount();
|
||||
} else await accountApi.renameDevice(device.id, names[device.id] ?? device.name);
|
||||
await refresh();
|
||||
} catch (cause) { setError(cause instanceof Error ? cause.message : '设备更新失败'); }
|
||||
finally { setBusy(false); }
|
||||
}
|
||||
return <section aria-label="账号设备"><strong>我的设备</strong>
|
||||
<p className={styles.note}>同一账号可登录多台设备。移除设备会撤销它的登录与空间席位,保留账号的空间成员资格。</p>
|
||||
{devices.map((device) => <div className={styles.actions} key={device.id}>
|
||||
<input aria-label={`${device.name} 的设备名称`} maxLength={80} value={names[device.id] ?? device.name} onChange={(e) => setNames((values) => ({ ...values, [device.id]: e.target.value }))} />
|
||||
<span>{device.current ? '本机' : '其他设备'}</span>
|
||||
<Button disabled={busy} onClick={() => { void change(device, false); }}>重命名</Button>
|
||||
<Button variant="ghost" disabled={busy || device.current} onClick={() => {
|
||||
if (window.confirm(`移除设备「${device.name}」并撤销它的登录?`)) void change(device, true);
|
||||
}}>移除设备</Button>
|
||||
</div>)}
|
||||
<Button variant="ghost" disabled={busy} onClick={() => { void refresh().catch(() => setError('设备清单读取失败')); }}>刷新设备</Button>
|
||||
{error ? <p className={styles.error} role="alert">{error}</p> : null}
|
||||
</section>;
|
||||
}
|
||||
Reference in new issue
Block a user