Files
WebDrop/web/src/features/share/ShareView.tsx
T

87 lines
3.6 KiB
TypeScript

import { lazy, Suspense, useCallback, useState } from 'react';
import { CompactRow } from '@/features/item/CompactRow';
import { useDownload } from '@/features/item/download';
import { formatRemaining } from '@/lib/format';
import { useShareSession } from '@/store/shareSession';
import { Button } from '@/ui/Button';
import { CopyButton } from '@/ui/CopyButton';
import { Icon } from '@/ui/Icon';
import { QrCode } from '@/ui/QrCode';
import { ShareBar } from './ShareBar';
import styles from './ShareView.module.css';
const PreviewSheet = lazy(() => import('@/features/item/PreviewSheet'));
const noop = () => {};
/** 已封存的分享:只读。访客与创建者看到的清单相同,创建者多一张「分享给别人」卡片 */
export function ShareView() {
const share = useShareSession((s) => s.share);
const ids = useShareSession((s) => s.order);
const integrityError = useShareSession((s) => s.integrityError);
const error = useShareSession((s) => s.error);
const download = useDownload();
const [sheetId, setSheetId] = useState<string>();
const [showQr, setShowQr] = useState(true);
const closeSheet = useCallback(() => setSheetId(undefined), []);
if (!share) return null;
const remaining = formatRemaining(share.expiresAt);
async function downloadAll() {
const { byId } = useShareSession.getState();
for (const id of ids) {
const item = byId[id];
if (item) await download(item);
await new Promise((r) => setTimeout(r, 300)); // 浏览器会拦截太密集的多文件下载
}
}
return (
<div className={styles.page}>
<ShareBar
title={share.mine ? '我的分享' : '收到的分享'}
badge={<span className={styles.badge}><Icon name="lock" size={12} /> 已封存 · 只读</span>}
/>
<main className={styles.main}>
{integrityError ? <p className={styles.error} role="alert">{integrityError}</p> : null}
{error ? <p className={styles.error} role="alert">{error}</p> : null}
{share.mine ? (
<section className={styles.share} aria-label="分享给别人">
<h2 className={styles.h}>分享给别人</h2>
<code className={styles.link}>{share.link}</code>
<div className={styles.row}>
<CopyButton text={share.link} variant="primary" label="复制链接" />
<Button variant="ghost" icon="scan" aria-expanded={showQr} onClick={() => setShowQr((v) => !v)}>
{showQr ? '收起二维码' : '二维码'}
</Button>
</div>
{showQr ? <QrCode text={share.link} label="分享链接二维码" /> : null}
<p className={styles.dim}>
访客只能预览和下载。内容已封存,你也不能再修改或删除,{remaining}后自动清除。持有链接的人都能下载。
</p>
</section>
) : (
<p className={styles.note}>
这是一个只读分享:内容不会再被修改,{remaining}后自动清除。
</p>
)}
<div className={styles.head}>
<span>{ids.length} 项内容</span>
<Button variant="primary" icon="download" onClick={() => void downloadAll()} disabled={ids.length === 0}>全部下载</Button>
</div>
<ul className={styles.list}>
{ids.map((id) => (
<CompactRow key={id} id={id} selected={false} onSelect={setSheetId} />
))}
</ul>
</main>
<Suspense fallback={null}>
{sheetId ? <PreviewSheet id={sheetId} onClose={closeSheet} readOnly onDelete={noop} /> : null}
</Suspense>
</div>
);
}