"use client";
import { useMemo, useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { useLocale, useTranslations } from "next-intl";
import { useIsRtl } from "@/lib/use-is-rtl";
import { Box, Pencil, Plus, Search, Video, X } from "lucide-react";
import { DemoDataBanner } from "@/components/demo/demo-data-banner";
import { Menu3dUpload } from "@/components/media/menu-3d-upload";
import { MenuAi3dGenerate } from "@/components/media/menu-ai-3d-generate";
import { CategoryVisual } from "@/components/menu/category-visual";
import { CategoryMediaFields } from "@/components/menu/category-media-fields";
import type { CategoryIconSelection } from "@/components/menu/category-preset-picker";
import { DEFAULT_CATEGORY_ICON_STYLE } from "@/lib/category-icon-presets";
import { ApiClientError, apiGet, apiPatch, apiPost } from "@/lib/api/client";
import { notify } from "@/lib/notify";
import { useAuthStore } from "@/lib/stores/auth.store";
import { useBranchStore } from "@/lib/stores/branch.store";
import { formatCurrency, formatNumber } from "@/lib/format";
import { PageHeader } from "@/components/layout/page-header";
import { MediaPairUpload } from "@/components/media/media-pair-upload";
import { Button } from "@/components/ui/button";
import { Input } from "@/components/ui/input";
import { LabeledField } from "@/components/ui/labeled-field";
import { Skeleton } from "@/components/ui/skeleton";
import { cn } from "@/lib/utils";
import { MenuItemLabels } from "@/components/menu/menu-item-labels";
import { MenuItemMedia } from "@/components/menu/menu-item-media";
import { buildCategoryNameMap, inferMenuItemKind } from "@/lib/menu-item-image";
import { menuItemMatchesSearch } from "@/lib/menu-display";
import { BranchMenuOverrides } from "@/components/menu/branch-menu-overrides";
// ─── Types ────────────────────────────────────────────────────────────────────
interface MenuCategory {
id: string;
name: string;
nameEn?: string;
nameAr?: string;
sortOrder: number;
discountPercent: number;
icon?: string;
iconPresetId?: string;
iconStyle?: string;
imageUrl?: string;
isActive: boolean;
}
interface MenuItem {
id: string;
categoryId: string;
name: string;
nameEn?: string;
nameAr?: string;
price: number;
discountPercent: number;
imageUrl?: string;
videoUrl?: string;
model3dUrl?: string;
isAvailable: boolean;
}
interface ItemForm {
categoryId: string;
name: string;
nameEn: string;
price: string;
discount: string;
imageUrl: string;
videoUrl: string;
model3dUrl: string;
}
interface CatForm {
name: string;
icon: string;
iconPreset: CategoryIconSelection;
imageUrl: string;
}
// ─── Helpers ──────────────────────────────────────────────────────────────────
function discountedPrice(price: number, percent: number) {
if (percent <= 0) return price;
return Math.round(price * (1 - percent / 100));
}
function mediaField(url: string) {
return url.trim() === "" ? "" : url;
}
const defaultItemForm: ItemForm = {
categoryId: "",
name: "",
nameEn: "",
price: "",
discount: "0",
imageUrl: "",
videoUrl: "",
model3dUrl: "",
};
const defaultCatForm: CatForm = {
name: "",
icon: "",
iconPreset: { iconPresetId: null, iconStyle: DEFAULT_CATEGORY_ICON_STYLE },
imageUrl: "",
};
// ─── Toggle Switch ────────────────────────────────────────────────────────────
function ToggleSwitch({
checked,
onChange,
disabled,
label,
}: {
checked: boolean;
onChange: (v: boolean) => void;
disabled?: boolean;
label?: string;
}) {
return (
);
}
// ─── Modal wrapper ────────────────────────────────────────────────────────────
function Modal({
open,
onClose,
title,
children,
maxWidth = "max-w-lg",
}: {
open: boolean;
onClose: () => void;
title: string;
children: React.ReactNode;
maxWidth?: string;
}) {
if (!open) return null;
return (
);
}
// ─── Main Component ───────────────────────────────────────────────────────────
export function MenuAdminScreen() {
const t = useTranslations("menuAdmin");
const tCommon = useTranslations("common");
const tNotify = useTranslations("notify");
const showError = (err: unknown) =>
notify.error(
err instanceof ApiClientError ? err.message : tNotify("errorGeneric")
);
const isRtl = useIsRtl();
const locale = useLocale();
const numberLocale = locale === "en" ? "en-US" : "fa-IR";
const cafeId = useAuthStore((s) => s.user?.cafeId);
const branchId = useBranchStore((s) => s.branchId);
const queryClient = useQueryClient();
// ── UI state ───────────────────────────────────────────────────────────────
const [activeTab, setActiveTab] = useState<"catalog" | "branch">("catalog");
const [selectedCategoryId, setSelectedCategoryId] = useState("all");
const [itemSearch, setItemSearch] = useState("");
// Item modal
const [itemModalOpen, setItemModalOpen] = useState(false);
const [editingItem, setEditingItem] = useState