import { useQueryClient } from "@tanstack/react-query"; import { Link } from "@tanstack/react-router"; import { Copy, Download, MoreVertical, Play, Trash2 } from "lucide-react"; import { useEffect, useRef, useState } from "react"; import { toast } from "sonner"; import { DeleteDeckDialog } from "@/components/deck/DeleteDeckDialog"; import type { Rkey } from "@/lib/atproto-client"; import { getCardDataProvider } from "@/lib/card-data-provider"; import { prefetchCards } from "@/lib/card-prefetch"; import { useCreateDeckMutation, useDeleteDeckMutation, } from "@/lib/deck-queries"; import type { Deck } from "@/lib/deck-types"; import { findAllCanonicalPrintings, findAllCheapestPrintings, updateDeckPrintings, } from "@/lib/printing-selection"; import type { ScryfallId } from "@/lib/scryfall-types"; import { useAuth } from "@/lib/useAuth"; interface DeckActionsMenuProps { deck: Deck; did: string; rkey: Rkey; onUpdateDeck?: (updater: (prev: Deck) => Deck) => Promise; onCardsChanged?: (changedIds: Set) => void; readOnly?: boolean; } export function DeckActionsMenu({ deck, did, rkey, onUpdateDeck, onCardsChanged, readOnly = false, }: DeckActionsMenuProps) { const { session } = useAuth(); const queryClient = useQueryClient(); const [isOpen, setIsOpen] = useState(false); const [showDeleteDialog, setShowDeleteDialog] = useState(false); const menuRef = useRef(null); const deleteMutation = useDeleteDeckMutation(rkey); const cloneMutation = useCreateDeckMutation(); useEffect(() => { const handleClickOutside = (event: MouseEvent) => { if (menuRef.current && !menuRef.current.contains(event.target as Node)) { setIsOpen(false); } }; if (isOpen) { document.addEventListener("mousedown", handleClickOutside); return () => document.removeEventListener("mousedown", handleClickOutside); } }, [isOpen]); const handleSetAllToCheapest = async () => { if (!onUpdateDeck) return; setIsOpen(false); const toastId = toast.loading("Finding cheapest printings..."); try { const provider = await getCardDataProvider(); const updates = await findAllCheapestPrintings(deck, provider); if (updates.size > 0) { const newIds = [...new Set(updates.values())]; await prefetchCards(queryClient, newIds); await onUpdateDeck((prev) => updateDeckPrintings(prev, updates)); onCardsChanged?.(new Set(newIds)); toast.success(`Updated ${updates.size} printing(s)`, { id: toastId }); } else { toast.success("All cards already at cheapest", { id: toastId }); } } catch { toast.error("Failed to update printings", { id: toastId }); } }; const handleSetAllToBest = async () => { if (!onUpdateDeck) return; setIsOpen(false); const toastId = toast.loading("Finding best printings..."); try { const provider = await getCardDataProvider(); const updates = await findAllCanonicalPrintings(deck, provider); if (updates.size > 0) { const newIds = [...new Set(updates.values())]; await prefetchCards(queryClient, newIds); await onUpdateDeck((prev) => updateDeckPrintings(prev, updates)); onCardsChanged?.(new Set(newIds)); toast.success(`Updated ${updates.size} printing(s)`, { id: toastId }); } else { toast.success("All cards already at best", { id: toastId }); } } catch { toast.error("Failed to update printings", { id: toastId }); } }; const handleClone = () => { setIsOpen(false); const cloneName = `Copy of ${deck.name}`; cloneMutation.mutate( { name: cloneName, format: deck.format, primer: deck.primer, cards: deck.cards, }, { onSuccess: () => toast.success(`Created "${cloneName}"`), }, ); }; return (
{isOpen && (
setIsOpen(false)} > Playtest setIsOpen(false)} > Export {session && ( )} {!readOnly && ( <>
)}
)} setShowDeleteDialog(false)} onConfirm={() => deleteMutation.mutate()} isDeleting={deleteMutation.isPending} />
); }