Files
waste-go/web/src/components/ShareManager.tsx

119 lines
3.7 KiB
TypeScript
Raw Normal View History

import { useState, useEffect, useRef } from 'react'
import { useWaste } from '../store'
interface ShareRecord {
name: string // display name (folder name picked by user)
global: boolean // true = all networks
networkId?: string
}
const STORAGE_KEY = 'waste_shares'
function loadShares(): ShareRecord[] {
try {
return JSON.parse(localStorage.getItem(STORAGE_KEY) ?? '[]')
} catch {
return []
}
}
function saveShares(shares: ShareRecord[]) {
localStorage.setItem(STORAGE_KEY, JSON.stringify(shares))
}
export function ShareManager() {
const { activeNetworkId, setSharedFiles, sharedFilesByNetwork } = useWaste()
const [shares, setShares] = useState<ShareRecord[]>(loadShares)
const [includeSubfolders, setIncludeSubfolders] = useState(true)
const inputRef = useRef<HTMLInputElement>(null)
// Count files currently shared on active network
const current = activeNetworkId ? sharedFilesByNetwork[activeNetworkId] : undefined
const fileCount = current?.size ?? 0
function persist(next: ShareRecord[]) {
setShares(next)
saveShares(next)
}
function addShare(files: FileList, folderName: string) {
const map = new Map<string, File>()
for (let i = 0; i < files.length; i++) {
const f = files[i]
const rel = (f as File & { webkitRelativePath?: string }).webkitRelativePath
const path = rel ? rel.split('/').slice(1).join('/') : f.name
if (!includeSubfolders && path.includes('/')) continue
map.set(path, f)
}
setSharedFiles(map)
const record: ShareRecord = {
name: folderName,
global: true,
networkId: activeNetworkId ?? undefined,
}
persist([...shares.filter(s => s.name !== folderName), record])
}
function removeShare(name: string) {
persist(shares.filter(s => s.name !== name))
// Clear the in-memory share if it matches
setSharedFiles(new Map())
}
function onChange(e: React.ChangeEvent<HTMLInputElement>) {
const fileList = e.target.files
if (!fileList || fileList.length === 0) return
// Get folder name from first file's path
const first = fileList[0] as File & { webkitRelativePath?: string }
const folderName = first.webkitRelativePath?.split('/')[0] ?? 'folder'
addShare(fileList, folderName)
e.target.value = ''
}
return (
<div className="share-manager">
<input
ref={inputRef}
type="file"
// @ts-expect-error webkitdirectory is non-standard
webkitdirectory=""
multiple
style={{ display: 'none' }}
onChange={onChange}
/>
{shares.length > 0 && (
<ul className="share-list">
{shares.map(s => (
<li key={s.name} className="share-item">
<span className="share-icon">📁</span>
<span className="share-name" title={s.name}>{s.name}</span>
<span className="share-scope">{s.global ? 'all nets' : 'this net'}</span>
<button className="share-repick" onClick={() => inputRef.current?.click()} title="Re-pick folder"></button>
<button className="share-remove" onClick={() => removeShare(s.name)} title="Remove share"></button>
</li>
))}
</ul>
)}
<button
className="folder-picker-btn"
onClick={() => inputRef.current?.click()}
title="Share a folder with peers on this network"
>
{fileCount > 0 ? `${fileCount} file${fileCount !== 1 ? 's' : ''} shared` : '+ Share folder'}
</button>
<label className="folder-picker-subfolders">
<input
type="checkbox"
checked={includeSubfolders}
onChange={e => setIncludeSubfolders(e.target.checked)}
/>
include subfolders
</label>
</div>
)
}