"use client"; import { useEffect, useMemo, useState } from "react"; import Link from "next/link"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; import { toast } from "sonner"; import { Button, Card, CardContent, Input, PageHeader, Textarea, Badge, Label } from "@/components/ds"; import { HospitalityBreadcrumbs } from "@/modules/hospitality/components/HospitalityBreadcrumbs"; import { HospitalityPageLoader, HospitalityPageError } from "@/modules/hospitality/pages/shared"; import { hospitalityApi } from "@/modules/hospitality/services/hospitality-api"; import { useTenantId } from "@/hooks/useTenantId"; import { useHospitalityProductBrand } from "@/modules/hospitality/hooks/useHospitalityProductBrand"; import { cn } from "@/lib/utils"; const STEPS = [ { id: "profile", label: "پروفایل کسب‌وکار" }, { id: "hours", label: "ساعات کار" }, { id: "taxes", label: "مالیات" }, { id: "menu", label: "منو" }, { id: "integrations", label: "یکپارچه‌سازی‌ها" }, { id: "checklist", label: "چک‌لیست" }, ] as const; type StepId = (typeof STEPS)[number]["id"]; export function RestaurantOnboardingPage() { const { tenantId } = useTenantId(); const brand = useHospitalityProductBrand(); const qc = useQueryClient(); const [step, setStep] = useState("profile"); const [venueName, setVenueName] = useState(""); const [venueCode, setVenueCode] = useState(""); const [address, setAddress] = useState(""); const [hoursJson, setHoursJson] = useState('{"sat":"09:00-23:00","sun":"09:00-23:00"}'); const [taxJson, setTaxJson] = useState('{"vat_percent":9}'); const venuesQ = useQuery({ queryKey: ["hospitality", tenantId, "onboarding-venues"], queryFn: () => hospitalityApi.venues.list(tenantId!, { page: 1, page_size: 50 }), enabled: !!tenantId, }); const menusQ = useQuery({ queryKey: ["hospitality", tenantId, "onboarding-menus"], queryFn: () => hospitalityApi.menus.list(tenantId!, { page: 1, page_size: 50 }), enabled: !!tenantId, }); const settingsQ = useQuery({ queryKey: ["hospitality", tenantId, "onboarding-settings"], queryFn: () => hospitalityApi.settings.list(tenantId!, { page: 1, page_size: 200 }), enabled: !!tenantId, }); const connectorsQ = useQuery({ queryKey: ["hospitality", tenantId, "onboarding-connectors"], queryFn: () => hospitalityApi.connectorRegistrations.list(tenantId!, { page: 1, page_size: 100 }), enabled: !!tenantId, }); const primaryVenue = venuesQ.data?.[0]; useEffect(() => { if (!primaryVenue) return; setVenueName(String(primaryVenue.name || "")); setVenueCode(String(primaryVenue.code || "")); const meta = primaryVenue.metadata as Record | undefined; setAddress(String(primaryVenue.address || meta?.address || "")); }, [primaryVenue]); const createVenue = useMutation({ mutationFn: async () => { if (!tenantId) throw new Error("tenant"); return hospitalityApi.venues.create(tenantId, { code: venueCode || `venue-${Date.now()}`, name: venueName || "رستوران", format: "restaurant", status: "active", metadata: { address, source: "hospitality_onboarding" }, }); }, onSuccess: () => { toast.success("مکان ایجاد شد"); void qc.invalidateQueries({ queryKey: ["hospitality", tenantId] }); setStep("hours"); }, onError: (e: Error) => toast.error(e.message), }); const upsertSetting = useMutation({ mutationFn: async (payload: { key: string; value: unknown }) => { if (!tenantId) throw new Error("tenant"); return hospitalityApi.settings.upsert(tenantId, { key: payload.key, value: payload.value, venue_id: primaryVenue?.id, }); }, onSuccess: () => { toast.success("تنظیمات ذخیره شد"); void qc.invalidateQueries({ queryKey: ["hospitality", tenantId, "onboarding-settings"] }); }, onError: (e: Error) => toast.error(e.message), }); const createMenu = useMutation({ mutationFn: async () => { if (!tenantId || !primaryVenue?.id) throw new Error("venue_required"); return hospitalityApi.menus.create(tenantId, { code: `menu-${Date.now()}`, name: "منوی اصلی", venue_id: primaryVenue.id, status: "draft", }); }, onSuccess: () => { toast.success("منوی پیش‌نویس ساخته شد"); void qc.invalidateQueries({ queryKey: ["hospitality", tenantId] }); setStep("integrations"); }, onError: (e: Error) => toast.error(e.message), }); const checklist = useMemo(() => { const settings = settingsQ.data || []; const hasHours = settings.some((s) => String(s.key).includes("working_hours")); const hasTax = settings.some((s) => String(s.key).includes("tax")); const kinds = new Set((connectorsQ.data || []).map((c) => String(c.kind))); return [ { id: "venue", label: "پروفایل / مکان", done: (venuesQ.data?.length || 0) > 0, href: "/hospitality/branches" }, { id: "hours", label: "ساعات کار", done: hasHours, href: "/hospitality/settings" }, { id: "tax", label: "مالیات", done: hasTax, href: "/hospitality/settings" }, { id: "menu", label: "منو", done: (menusQ.data?.length || 0) > 0, href: "/hospitality/menu" }, { id: "payment", label: "پرداخت POS (محلی)", done: false, href: "/hospitality/pos/register", hint: "پرداخت PSP از سرویس Payment — POS محلی Hospitality" }, { id: "qr", label: "QR", done: false, href: "/hospitality/qr/menu", hint: "پس از منو از QR بسازید" }, { id: "delivery", label: "پیک", done: kinds.has("delivery"), href: "/hospitality/integrations/delivery" }, { id: "loyalty", label: "وفاداری", done: kinds.has("loyalty"), href: "/hospitality/integrations/loyalty" }, { id: "crm", label: "CRM", done: kinds.has("crm"), href: "/hospitality/integrations/crm" }, { id: "communication", label: "ارتباطات", done: kinds.has("communication"), href: "/hospitality/integrations/communication" }, { id: "printer", label: "پرینتر / station", done: false, href: "/hospitality/pos/pro", hint: "POS stations در بسته POS Pro" }, ]; }, [venuesQ.data, menusQ.data, settingsQ.data, connectorsQ.data]); const doneCount = checklist.filter((c) => c.done).length; const pct = Math.round((doneCount / checklist.length) * 100); if (!tenantId || venuesQ.isLoading) return ; if (venuesQ.error) return venuesQ.refetch()} />; const productLabel = brand.data?.displayName || "محصول Hospitality"; return (
{pct}% تکمیل} />
{STEPS.map((s) => ( ))}
{step === "profile" ? (

{primaryVenue ? "مکان موجود یافت شد — می‌توانید ادامه دهید یا مکان جدید بسازید." : "هنوز مکانی نیست. نام، کد و آدرس را وارد کنید."}

setVenueName(e.target.value)} />
setVenueCode(e.target.value)} dir="ltr" />