import Button from "@/components/Button"; import ColorPicker from "@/components/ColorPicker"; import Radio from "@/components/Radio"; import { extractErrorMessage } from "@/config/func"; import type { ErrorType } from "@/helpers/types"; import { clx } from "@/helpers/utils"; import DesignSlider from "@/pages/settings/components/DesignSlider"; import { getBackgroundPatternUrl, PATTERN_BACKGROUND_OPACITY, useBackgroundPatterns } from "@/pages/settings/hooks/usePatterns"; import { useGetBackgrounds, useGetRestaurant, useSetBackground, useUpdateRestaurant } from "@/pages/settings/hooks/useSettingData"; import type { BackgroundItemType, SetBackgroundType } from "@/pages/settings/types/Types"; import { useSingleUpload } from "@/pages/uploader/hooks/useUploaderData"; import { DocumentUpload, Gallery, TickCircle, Trash } from "iconsax-react"; import { useCallback, useEffect, useMemo, useState, type FC } from "react"; import { useDropzone } from "react-dropzone"; import { toast } from "react-toastify"; const COLOR_APPLY_DELAY_MS = 500; type BackgroundType = "pattern" | "custom"; const UPLOAD_BOX_CLASS = "w-[200px] h-[362px] rounded-2xl border border-dashed border-description"; const getPatternBgUrl = (item: BackgroundItemType) => item.url ?? item.bgUrl ?? ""; const normalizeBgUrl = (url: string) => { if (!url) return ""; if (url.startsWith("http")) return url; return `${import.meta.env.VITE_BASE_URL}${url.startsWith("/") ? url : `/${url}`}`; }; const DesignSettings: FC = () => { const [menuColor, setMenuColor] = useState("#000000"); const [appliedColor, setAppliedColor] = useState("#000000"); const [selectedPatternId, setSelectedPatternId] = useState(null); const [backgroundType, setBackgroundType] = useState("pattern"); const [customImage, setCustomImage] = useState(null); const [customImagePreview, setCustomImagePreview] = useState(null); const [existingBgUrl, setExistingBgUrl] = useState(null); const [imageOpacity, setImageOpacity] = useState(100); const [imageBlur, setImageBlur] = useState(0); const [overlayDarkness, setOverlayDarkness] = useState(0); const [isInitialized, setIsInitialized] = useState(false); const { data: backgrounds } = useGetBackgrounds(); const { mutate: setBackground, isPending: isSavingBackground } = useSetBackground(); const { mutate: updateRestaurant, isPending: isUpdatingRestaurant } = useUpdateRestaurant(); const { mutate: singleUpload, isPending: isUploadingImage } = useSingleUpload(); const { patterns, isLoading: isPatternsLoading, isError: isPatternsError } = useBackgroundPatterns(appliedColor); const { data: restaurant, refetch } = useGetRestaurant(); const backgroundItems = useMemo(() => backgrounds?.data ?? [], [backgrounds]); const isSaving = isSavingBackground || isUploadingImage || isUpdatingRestaurant; useEffect(() => { if (!restaurant?.data || isInitialized) return; const restaurantData = restaurant.data; const savedBgUrl = restaurantData.bgUrl; if (savedBgUrl && backgroundItems.length === 0) return; const color = restaurantData.menuColor || "#000000"; setMenuColor(color); setAppliedColor(color); if (savedBgUrl) { const matchingPattern = backgroundItems.find((item) => getBackgroundPatternUrl(item) === normalizeBgUrl(savedBgUrl) || getPatternBgUrl(item) === savedBgUrl); if (matchingPattern) { setBackgroundType("pattern"); setSelectedPatternId(matchingPattern.id); } else { setBackgroundType("custom"); setExistingBgUrl(savedBgUrl); setCustomImagePreview(normalizeBgUrl(savedBgUrl)); setImageOpacity(Number(restaurantData.bgOpacity) || 100); setImageBlur(Number(restaurantData.bgBlur) || 0); setOverlayDarkness(Number(restaurantData.bgOverlay) || 0); } } else { setSelectedPatternId("0"); } setIsInitialized(true); }, [restaurant, backgroundItems, isInitialized]); useEffect(() => { const timer = setTimeout(() => setAppliedColor(menuColor), COLOR_APPLY_DELAY_MS); return () => clearTimeout(timer); }, [menuColor]); useEffect(() => { if (!customImage) return; const previewUrl = URL.createObjectURL(customImage); setCustomImagePreview(previewUrl); return () => URL.revokeObjectURL(previewUrl); }, [customImage]); const onDrop = useCallback((acceptedFiles: File[]) => { if (acceptedFiles[0]) { setCustomImage(acceptedFiles[0]); } }, []); const { getRootProps, getInputProps } = useDropzone({ onDrop, accept: { "image/*": [] }, multiple: false, }); const handleRemoveImage = () => { setCustomImage(null); setExistingBgUrl(null); setCustomImagePreview(null); setImageOpacity(100); setImageBlur(0); setOverlayDarkness(0); }; const saveCustomBackground = (bgUrl: string) => { const backgroundPayload: SetBackgroundType = { bgUrl, bgBlur: String(imageBlur ?? 0), bgOverlay: String(overlayDarkness ?? 0), }; if (imageOpacity) { backgroundPayload.bgOpacity = String(imageOpacity); } setBackground(backgroundPayload, { onSuccess: () => { toast.success("تنظیمات طراحی با موفقیت ذخیره شد"); refetch(); }, onError: (error: unknown) => { toast.error(extractErrorMessage(error as ErrorType, "خطا در ذخیره تنظیمات طراحی")); }, }); }; const handleApplyChanges = () => { updateRestaurant( { menuColor }, { onSuccess: () => { if (backgroundType === "pattern") { let bgUrl = ""; if (selectedPatternId !== "0") { const selectedItem = backgroundItems.find((item) => item.id === selectedPatternId); bgUrl = selectedItem ? getPatternBgUrl(selectedItem) : ""; if (!bgUrl) { toast.error("لطفاً یک پترن انتخاب کنید"); return; } } setBackground( { bgUrl }, { onSuccess: () => { toast.success("تنظیمات طراحی با موفقیت ذخیره شد"); refetch(); }, onError: (error: unknown) => { toast.error(extractErrorMessage(error as ErrorType, "خطا در ذخیره تنظیمات طراحی")); }, }, ); return; } if (customImage) { singleUpload(customImage, { onSuccess: (response) => { const bgUrl = response?.data?.url ?? ""; if (!bgUrl) { toast.error("خطا در آپلود تصویر"); return; } saveCustomBackground(bgUrl); }, onError: (error: ErrorType) => { toast.error(extractErrorMessage(error, "خطا در آپلود تصویر")); }, }); return; } if (existingBgUrl) { saveCustomBackground(existingBgUrl); return; } toast.error("لطفاً تصویر پس‌زمینه را آپلود کنید"); }, onError: (error: unknown) => { toast.error(extractErrorMessage(error as ErrorType, "خطا در ذخیره تنظیمات طراحی")); }, }, ); }; const isApplyDisabled = isSaving || (backgroundType === "pattern" ? !selectedPatternId : !customImage && !existingBgUrl); return (
تنظیمات طراحی
setBackgroundType(value as BackgroundType)} />
انتخاب پس زمینه
{backgroundType === "pattern" && (
{isPatternsLoading && Array.from({ length: 6 }).map((_, index) =>
)} {!isPatternsLoading && isPatternsError &&
خطا در بارگذاری پترن‌ها
} {!isPatternsLoading && !isPatternsError && patterns.length === 0 &&
پترنی یافت نشد
} {patterns.map((pattern) => ( ))}
)}
setBackgroundType(value as BackgroundType)} />
تصویر پس زمینه دلخواه
{backgroundType === "custom" && (
{!customImagePreview ? (
تصویر مورد نظر را آپلود کنید
آپلود
) : (
پس‌زمینه دلخواه {overlayDarkness > 0 &&
}
تنظیمات
)}
)}
); }; export default DesignSettings;