52 lines
2.1 KiB
TypeScript
52 lines
2.1 KiB
TypeScript
|
|
import { useWaste } from '../store'
|
||
|
|
|
||
|
|
function fmt(bytes: number): string {
|
||
|
|
if (bytes < 1024) return `${bytes} B`
|
||
|
|
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`
|
||
|
|
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`
|
||
|
|
}
|
||
|
|
|
||
|
|
export function Transfers() {
|
||
|
|
const { pendingOffers, fileProgress, acceptOffer, rejectOffer, cancelTransfer, connectedPeers } = useWaste()
|
||
|
|
|
||
|
|
const hasPending = Object.keys(pendingOffers).length > 0
|
||
|
|
const hasActive = Object.keys(fileProgress).length > 0
|
||
|
|
|
||
|
|
if (!hasPending && !hasActive) return null
|
||
|
|
|
||
|
|
function alias(peerId: string) {
|
||
|
|
return connectedPeers.find(p => p.id === peerId)?.alias ?? peerId.slice(0, 8)
|
||
|
|
}
|
||
|
|
|
||
|
|
return (
|
||
|
|
<div className="sidebar-section">
|
||
|
|
<span className="sidebar-label">Transfers</span>
|
||
|
|
|
||
|
|
{Object.entries(pendingOffers).map(([xid, offer]) => (
|
||
|
|
<div key={xid} className="transfer-row">
|
||
|
|
<span className="transfer-name" title={offer.name}>{offer.name}</span>
|
||
|
|
<span className="transfer-meta">{fmt(offer.size)} from {alias(offer.peerId)}</span>
|
||
|
|
<div className="transfer-actions">
|
||
|
|
<button className="transfer-btn accept" onClick={() => acceptOffer(offer.peerId, xid, offer.name, offer.size)}>Accept</button>
|
||
|
|
<button className="transfer-btn reject" onClick={() => rejectOffer(offer.peerId, xid)}>Reject</button>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
))}
|
||
|
|
|
||
|
|
{Object.entries(fileProgress).map(([xid, p]) => {
|
||
|
|
const pct = p.total > 0 ? Math.round((p.received / p.total) * 100) : 0
|
||
|
|
return (
|
||
|
|
<div key={xid} className="transfer-row">
|
||
|
|
<span className="transfer-name" title={p.name}>{p.name}</span>
|
||
|
|
<span className="transfer-meta">{fmt(p.received)} / {fmt(p.total)} · {alias(p.peerId)}</span>
|
||
|
|
<div className="transfer-progress">
|
||
|
|
<div className="transfer-progress-bar" style={{ width: `${pct}%` }} />
|
||
|
|
</div>
|
||
|
|
<button className="transfer-btn reject" onClick={() => cancelTransfer(p.peerId, xid, 'recv')}>Cancel</button>
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
})}
|
||
|
|
</div>
|
||
|
|
)
|
||
|
|
}
|