import type { Torrent } from '../shared'; import { useEffect, useState } from 'react'; import { X } from 'lucide-react'; import { Button } from '@/components/ui/button'; import { Dialog, DialogContent, DialogDescription, DialogFooter, DialogHeader, DialogTitle, } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; import { useTorrentMutations } from '../useTransmissionData'; // torrent-set replaces the whole labels array — there is no add/remove verb — so editing labels across a // multi-selection means deciding what "the labels" are for a set that may not agree. The dialog seeds from // the intersection and warns when the selection is not uniform, rather than silently flattening it. type LabelsDialogProps = { open: boolean; onOpenChange: (open: boolean) => void; targets: Torrent[]; /** Labels already in use anywhere, for one-click reuse. */ known: string[]; }; export const LabelsDialog = ({ open, onOpenChange, targets, known }: LabelsDialogProps) => { const { set } = useTorrentMutations(); const [labels, setLabels] = useState([]); const [draft, setDraft] = useState(''); const uniform = targets.length <= 1 || targets.every((t) => [...t.labels].sort().join('') === [...targets[0]!.labels].sort().join('')); useEffect(() => { if (!open) return; if (targets.length === 0) return setLabels([]); // The intersection: labels every selected torrent already has. Applying it unchanged is then a no-op // for a uniform selection and a deliberate flattening for a mixed one. const shared = targets[0]!.labels.filter((l) => targets.every((t) => t.labels.includes(l))); setLabels(shared); setDraft(''); }, [open, targets]); const add = (value: string) => { const clean = value.trim(); if (!clean || labels.includes(clean)) return; setLabels((prev) => [...prev, clean]); setDraft(''); }; const submit = async () => { await set.mutateAsync({ ids: targets.map((t) => t.id), labels }); onOpenChange(false); }; const unused = known.filter((k) => !labels.includes(k)); return ( Labels {targets.length === 1 ? targets[0]!.name : `${targets.length} torrents`}
{!uniform && (

These torrents have different labels. Saving replaces all of them with the set below.

)}
{labels.length === 0 && No labels.} {labels.map((l) => ( {l} ))}
setDraft(ev.target.value)} onKeyDown={(ev) => { if (ev.key === 'Enter') { ev.preventDefault(); add(draft); } }} placeholder="press enter to add" />
{unused.length > 0 && (
{unused.map((k) => ( ))}
)}
); };