import { useState } from 'react' import { useWaste } from '../store' import type { PeerStatus } from '../store' import { ShareManager } from './ShareManager' import { Transfers } from './Transfers' function makeYawCard(id: string, alias: string): string { const nick = encodeURIComponent(alias.trim().slice(0, 40)) return nick ? `yaw:${id}?n=${nick}` : `yaw:${id}` } function connDot(status: PeerStatus | undefined): { color: string; label: string } { const ct = status?.candidateType const cs = status?.connState if (cs === 'failed' || cs === 'closed') return { color: '#e06060', label: 'failed' } if (cs === 'connecting' || cs === 'new') return { color: '#c8a020', label: 'connecting…' } if (ct === 'relay') return { color: '#c8a020', label: 'relayed (TURN)' } if (ct === 'srflx') return { color: '#60c060', label: 'NAT punched' } if (ct === 'host') return { color: '#60c060', label: 'direct (LAN)' } if (cs === 'connected') return { color: '#60c060', label: 'connected' } return { color: 'var(--muted)', label: 'unknown' } } function formatTs(ts: number | undefined): string { if (!ts) return '—' return new Date(ts).toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }) } export function Sidebar() { const { localPeer, masterId, masterAlias, networks, activeNetworkId, activeRoom, connectedPeers, peerStatus, setActiveRoom, setActiveNetwork, messages, browseFiles, sendFileTo, adapterMode, customRooms, createRoom, logout, send, } = useWaste() const [addingRoom, setAddingRoom] = useState(false) const [newRoomName, setNewRoomName] = useState('') const [addingNetwork, setAddingNetwork] = useState(false) const [newNetName, setNewNetName] = useState('') const [newNetAnchor, setNewNetAnchor] = useState('') const netCustomRooms = activeNetworkId ? (customRooms[activeNetworkId] ?? []) : [] const rooms = ['general', ...netCustomRooms] if (activeNetworkId) { const prefix = `${activeNetworkId}:dm:` Object.keys(messages).forEach(k => { if (k.startsWith(prefix)) { const r = k.slice(activeNetworkId.length + 1) if (!rooms.includes(r)) rooms.push(r) } }) } function submitNewRoom(e: React.FormEvent) { e.preventDefault() if (newRoomName.trim()) createRoom(newRoomName) setNewRoomName('') setAddingRoom(false) } function submitNewNetwork(e: React.FormEvent) { e.preventDefault() const name = newNetName.trim() if (!name) return if (adapterMode === 'browser') { // Persist to saved networks list in localStorage. const anchor = newNetAnchor.trim() || localStorage.getItem('waste_anchor_url') || '' const saved: Array<{name: string; anchor: string}> = JSON.parse(localStorage.getItem('waste_saved_networks') ?? '[]') if (!saved.some(n => n.name === name && n.anchor === anchor)) { saved.push({ name, anchor }) localStorage.setItem('waste_saved_networks', JSON.stringify(saved)) } } send({ type: 'join_network', network_name: name }) setNewNetName('') setNewNetAnchor('') setAddingNetwork(false) } const displayAlias = localPeer?.alias ?? masterAlias ?? '' const displayId = localPeer?.id ?? masterId ?? '' const card = displayId ? makeYawCard(displayId, displayAlias) : null function copyHangLink() { const net = networks.find(n => n.network_id === activeNetworkId) if (!net) return const cfg = (window as unknown as { WASTE_CONFIG?: { signalURL?: string } }).WASTE_CONFIG const anchor = cfg?.signalURL ?? '' const payload = btoa(JSON.stringify({ network: net.network_name, anchor })) .replace(/\+/g, '-').replace(/\//g, '_') const url = `${window.location.origin}/#waste:${payload}` navigator.clipboard?.writeText(url) } function handleLogout() { const clearId = window.confirm('Also clear your identity keypair? (Cannot be undone — export a backup first if you want to keep it.)') logout(clearId) } function openDM(peerId: string) { setActiveRoom(`dm:${peerId}`) } function requestFiles(peerId: string) { browseFiles(peerId) } return ( ) }