/** * Quantity Limits Settings Page */ import { useState, useEffect, useCallback } from "react" import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs" import { Hash, Settings, ShoppingCart, FolderTree, MessageSquare, Loader2, Crown } from "lucide-react" import { toast } from "sonner" import { useQuantityLimitsSettings, useCartRules, useCategoryRules } from "../hooks" import { GeneralTab, CategoryRulesTab, CartRulesTab, MessagesTab, ProductsTab, QuantityLimitsUpgradeTab } from "./tabs" import type { CategoryRulesMap } from "./tabs/category-rules-tab" import { FeatureHeader } from "@/components/feature-header" import { usePro } from "@/contexts/pro-context" import { ProIndicator } from "@/components/pro/pro-indicator" import type { QuantityLimitsSettings, CartRules } from "../types" // Default settings for reset const defaultQuantityLimitsSettings: QuantityLimitsSettings = { enabled: false, show_notices: true, notice_style: 'info', block_checkout: true, combine_variations: false, min_qty_message: 'Minimum quantity required is {min}', max_qty_message: 'Maximum quantity allowed is {max}', step_qty_message: 'Quantity must be in multiples of {step}', min_order_qty_message: 'Minimum order quantity is {min}', max_order_qty_message: 'Maximum order quantity is {max}', min_order_total_message: 'Minimum order total is {min}', max_order_total_message: 'Maximum order total is {max}', category_min_message: 'Minimum quantity for {category} is {min}', category_max_message: 'Maximum quantity for {category} is {max}', } const defaultCartRules: CartRules = { min_qty_restriction: 0, max_qty_restriction: 0, enable_spend: false, min_spend: 0, max_spend: 0, include_shipping: false, excluded_products: [], } export function QuantityLimitsSettings() { const { isPro } = usePro() const { settings, isLoading: settingsLoading, isSaving: settingsSaving, saveSettings } = useQuantityLimitsSettings() const { rules: cartRules, isLoading: cartRulesLoading, isSaving: cartRulesSaving, saveRules: saveCartRules } = useCartRules() const { saveBulkCategoryRules } = useCategoryRules() const [localSettings, setLocalSettings] = useState(null) const [localCartRules, setLocalCartRules] = useState(defaultCartRules) const [localCategoryRules, setLocalCategoryRules] = useState({}) const [initialCategoryRules, setInitialCategoryRules] = useState({}) const [hasChanges, setHasChanges] = useState(false) // Initialize local state when data loads useEffect(() => { if (settings) { setLocalSettings(settings) } }, [settings]) useEffect(() => { if (cartRules) { setLocalCartRules(cartRules) } }, [cartRules]) // Handle categories loaded from CategoryRulesTab const handleCategoriesLoaded = useCallback((categories: Array<{ id: number; min_qty: string; max_qty: string; step_qty: string }>) => { const initial: CategoryRulesMap = {} categories.forEach((cat) => { initial[cat.id] = { min_qty: cat.min_qty || '', max_qty: cat.max_qty || '', step_qty: cat.step_qty || '' } }) setLocalCategoryRules(initial) setInitialCategoryRules(initial) }, []) // Track changes useEffect(() => { if (localSettings && settings) { const settingsChanged = JSON.stringify(localSettings) !== JSON.stringify(settings) const cartRulesChanged = cartRules ? JSON.stringify(localCartRules) !== JSON.stringify(cartRules) : false const categoryRulesChanged = JSON.stringify(localCategoryRules) !== JSON.stringify(initialCategoryRules) setHasChanges(settingsChanged || cartRulesChanged || categoryRulesChanged) } }, [localSettings, localCartRules, localCategoryRules, settings, cartRules, initialCategoryRules]) const handleSave = async () => { // Save general settings if (localSettings) { await saveSettings(localSettings) } // Save cart rules if (localCartRules) { await saveCartRules(localCartRules) } // Save category rules (bulk — single request for all changed categories) const changedCategoryRules = Object.entries(localCategoryRules) .filter(([categoryId, rule]) => { const initialRule = initialCategoryRules[parseInt(categoryId)] return JSON.stringify(rule) !== JSON.stringify(initialRule) }) .map(([categoryId, rule]) => ({ category_id: parseInt(categoryId), ...rule, })) if (changedCategoryRules.length > 0) { await saveBulkCategoryRules(changedCategoryRules) } // Update initial category rules to match current setInitialCategoryRules(localCategoryRules) toast.success("Settings saved", { description: "Your Quantity Limits settings have been saved successfully." }) setHasChanges(false) } const resetToDefaults = useCallback(() => { setLocalSettings(defaultQuantityLimitsSettings) }, []) const isLoading = settingsLoading || cartRulesLoading const isSaving = settingsSaving || cartRulesSaving if (isLoading) { return (
) } if (!localSettings) { return (
Failed to load settings. Please refresh the page.
) } return ( } title="Quantity Limits" description="Set minimum and maximum quantity rules for products, categories, and cart." documentationUrl="https://www.swiftcommerce.io/help/products/quantity-limits/" enabled={localSettings.enabled} onEnabledChange={(checked) => setLocalSettings({ ...localSettings, enabled: checked })} hasChanges={hasChanges} isSaving={isSaving} onSave={handleSave} onReset={resetToDefaults} > {/* Tabs */} General Products {isPro && ( Categories )} {isPro && ( Cart )} {isPro && ( Messages )} {!isPro && ( Upgrade to Pro )} {!isPro && ( )} ) }