"use client"; import { useState } from "react"; import { Sparkles } from "lucide-react"; import { useTranslations } from "next-intl"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { apiGet, apiPost, ApiClientError } from "@/lib/api/client"; import { Button } from "@/components/ui/button"; import { notify } from "@/lib/notify"; type MenuAi3dGenerateProps = { cafeId: string; itemId: string; imageUrl?: string | null; onGenerated: (model3dUrl: string) => void; }; type BillingStatus = { menu3dEnabled: boolean; menuAi3dEnabled: boolean; menuAi3dUsedThisMonth: number; menuAi3dMonthlyLimit: number; }; type Ai3dUsage = { used: number; limit: number; period: string; }; export function MenuAi3dGenerate({ cafeId, itemId, imageUrl, onGenerated, }: MenuAi3dGenerateProps) { const t = useTranslations("media"); const tSub = useTranslations("subscription"); const queryClient = useQueryClient(); const [busy, setBusy] = useState(false); const { data: billing } = useQuery({ queryKey: ["billing-status", cafeId], queryFn: () => apiGet("/api/billing/status"), enabled: !!cafeId, }); const { data: usage } = useQuery({ queryKey: ["menu-ai-3d-usage", cafeId], queryFn: () => apiGet(`/api/cafes/${cafeId}/menu/ai-3d/usage`), enabled: !!cafeId && (billing?.menuAi3dEnabled ?? false), }); const aiEnabled = billing?.menuAi3dEnabled ?? false; const used = usage?.used ?? billing?.menuAi3dUsedThisMonth ?? 0; const limit = usage?.limit ?? billing?.menuAi3dMonthlyLimit ?? 100; const atLimit = limit > 0 && used >= limit; const generate = useMutation({ mutationFn: () => apiPost<{ model3dUrl: string; used: number; limit: number }>( `/api/cafes/${cafeId}/menu/items/${itemId}/ai-3d`, {} ), onSuccess: (data) => { onGenerated(data.model3dUrl); void queryClient.invalidateQueries({ queryKey: ["billing-status", cafeId] }); void queryClient.invalidateQueries({ queryKey: ["menu-ai-3d-usage", cafeId] }); notify.success(t("ai3dSuccess")); }, onError: (err) => { if (err instanceof ApiClientError) { if (err.code === "PLAN_FEATURE_DISABLED") { notify.error(tSub("featureMenuAi3dUpgrade")); return; } if (err.code === "PLAN_LIMIT_REACHED") { notify.error(t("ai3dLimitReached")); return; } if (err.code === "NO_IMAGE") { notify.error(t("ai3dNoImage")); return; } } notify.error(t("ai3dFailed")); }, }); const handleClick = async () => { setBusy(true); try { await generate.mutateAsync(); } finally { setBusy(false); } }; if (!billing?.menu3dEnabled) return null; return (

{t("ai3dTitle")}

{t("ai3dHint")}

{!aiEnabled ? (

{tSub("featureMenuAi3dUpgrade")}

) : (

{t("ai3dUsage", { used: used.toLocaleString("fa-IR"), limit: limit.toLocaleString("fa-IR") })}

)} {!imageUrl ? (

{t("ai3dNoImage")}

) : null}
); }