"use client";
import { useState } from "react";
import { useRouter } from "next/navigation";
import { useTranslations } from "next-intl";
import { Pencil, Trash2 } from "lucide-react";
import { toast } from "sonner";
import { Button } from "@/components/ui/button";
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip";
import {
AlertDialog,
AlertDialogAction,
AlertDialogCancel,
AlertDialogContent,
AlertDialogDescription,
AlertDialogFooter,
AlertDialogHeader,
AlertDialogTitle,
} from "@/components/ui/alert-dialog";
import { Dialog, DialogContent, DialogHeader, DialogTitle } from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import { cn } from "@/lib/utils";
type Props = {
listId: string;
name: string;
/** Called after a successful rename, so the caller can update its own state. If omitted, falls back to router.refresh(). */
onRenamed?: (name: string) => void;
/** Called after a successful delete, so the caller can update its own state (e.g. remove the row). */
onDeleted?: () => void;
/** Path to navigate to after deleting (e.g. back to the list index from the detail page). */
redirectAfterDeleteTo?: string;
className?: string;
};
/** Owner-only rename/delete menu for a shopping list. Used on both the list index page and the list detail page. */
export function ShoppingListActionsMenu({ listId, name, onRenamed, onDeleted, redirectAfterDeleteTo, className }: Props) {
const t = useTranslations("shoppingLists");
const tCommon = useTranslations("common");
const router = useRouter();
const [renameOpen, setRenameOpen] = useState(false);
const [deleteOpen, setDeleteOpen] = useState(false);
const [newName, setNewName] = useState(name);
const [saving, setSaving] = useState(false);
const [deleting, setDeleting] = useState(false);
function openRename() {
setNewName(name);
setRenameOpen(true);
}
async function handleRename() {
const trimmed = newName.trim();
if (!trimmed || trimmed === name) {
setRenameOpen(false);
return;
}
setSaving(true);
try {
const res = await fetch(`/api/v1/shopping-lists/${listId}`, {
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ name: trimmed }),
});
if (!res.ok) throw new Error("failed");
toast.success(t("listRenamed"));
setRenameOpen(false);
if (onRenamed) onRenamed(trimmed);
else router.refresh();
} catch {
toast.error(t("listRenameFailed"));
} finally {
setSaving(false);
}
}
async function handleDelete() {
setDeleting(true);
try {
const res = await fetch(`/api/v1/shopping-lists/${listId}`, { method: "DELETE" });
if (!res.ok) throw new Error("failed");
toast.success(t("listDeleted"));
setDeleteOpen(false);
onDeleted?.();
if (redirectAfterDeleteTo) router.push(redirectAfterDeleteTo);
else router.refresh();
} catch {
toast.error(t("listDeleteFailed"));
setDeleting(false);
}
}
// Rows on the index page are wrapped in a Link — stop the click from bubbling to it
// and prevent the anchor's default navigation.
function stopRowNavigation(e: React.MouseEvent) {
e.preventDefault();
e.stopPropagation();
}
return (
<>