import { useState } from "react" import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Label } from "@/components/ui/label" import { Input } from "@/components/ui/input" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { TemplateGrid, Template } from "@/components/ui/template-grid" import { LivePreview as LivePreviewContainer } from "@/components/ui/live-preview" import { Collapsible, CollapsibleContent, CollapsibleTrigger } from "@/components/ui/collapsible" import { GlobalColorPicker } from "@/components/ui/global-color-picker" import { GlobalTypographyPicker } from "@/components/ui/global-typography-picker" import { RadioGroup, RadioGroupItem } from "@/components/ui/radio-group" import { Button } from "@/components/ui/button" import { Switch } from "@/components/ui/switch" import { Palette, Type, Square, Maximize2, LayoutTemplate, Layers, X, ChevronDown, AlignLeft, AlignCenter, AlignRight, Minus, Plus, RotateCcw, Sparkles, Image, CheckCircle2, } from "lucide-react" import { usePro } from "@/contexts/pro-context" import { ProIndicator } from "@/components/pro/pro-indicator" import { AddedToCartPopupPreview } from "../popup-preview" import { PopupStyleSettings, AddedToCartSettings, fontSizeOptions, borderRadiusOptions, shadowOptions, stylePresets } from "../../config" interface CustomizationTabProps { styles: PopupStyleSettings popupDesign: AddedToCartSettings['popupDesign'] updateStyles: (key: K, value: PopupStyleSettings[K]) => void resetStyles: () => void // Button & heading state for Live Preview (controls moved to Settings tab) showViewCartButton: boolean showCheckoutButton: boolean showContinueShoppingButton: boolean viewCartButtonText: string checkoutButtonText: string continueShoppingButtonText: string popupHeadingText: string showSuccessIcon: boolean cartDisplay: AddedToCartSettings['cartDisplay'] showRelatedProducts: boolean relatedProductsCount: number animationDuration: number updateSettings: (key: K, value: AddedToCartSettings[K]) => void } /** Compact number input with +/- buttons — replaces Slider */ function NumberStepper({ label, value, onChange, min, max, step = 1, unit = 'px', }: { label: string value: number onChange: (v: number) => void min: number max: number step?: number unit?: string }) { const clamp = (v: number) => Math.min(max, Math.max(min, v)) return (
{label && }
{ const parsed = parseInt(e.target.value, 10) if (!isNaN(parsed)) onChange(clamp(parsed)) }} className="h-8 w-14 text-center text-sm border-x bg-transparent outline-none" />
) } export function CustomizationTab({ styles, popupDesign, updateStyles, resetStyles, showViewCartButton, showCheckoutButton, showContinueShoppingButton, viewCartButtonText, checkoutButtonText, continueShoppingButtonText, popupHeadingText, showSuccessIcon, cartDisplay, showRelatedProducts, relatedProductsCount, animationDuration, updateSettings }: CustomizationTabProps) { const { isPro } = usePro() // Accordion state for custom styling sections const [expandedSections, setExpandedSections] = useState>({ content: false, colors: false, buttons: false, background: false, typography: false, spacing: false, border: false, icon: false, closeButton: false, animation: false, textAlignment: false, }) const toggleSection = (key: string) => { setExpandedSections(prev => ({ ...prev, [key]: !prev[key] })) } // Build templates list — 3 Free presets const templates: Template[] = stylePresets.map(preset => ({ id: preset.id, name: preset.name, description: preset.description, })) // Apply a preset template const applyPreset = (presetId: string) => { updateSettings('popupDesign', presetId as AddedToCartSettings['popupDesign']) const preset = stylePresets.find(p => p.id === presetId) if (preset) { Object.entries(preset.styles).forEach(([key, value]) => { if (value !== undefined) { updateStyles(key as keyof PopupStyleSettings, value as PopupStyleSettings[keyof PopupStyleSettings]) } }) } } // Preview props const previewProps = { styles, showViewCartButton, showCheckoutButton, showContinueShoppingButton, viewCartButtonText, checkoutButtonText, continueShoppingButtonText, headingText: popupHeadingText || 'Product added to cart!', showSuccessIcon, showRelatedProducts, relatedProductsCount, } return (
{/* Left Column - Options */}
{/* Template Selection */} Templates Choose a pre-designed style for your popup {/* Customize Design — always visible (no Custom mode gating) */}
Customize Design {isPro ? 'Fine-tune every aspect of your popup design' : 'Customize the colors of your popup design'}
{/* Content Section — Always Free */} toggleSection('content')}> Content
updateSettings('popupHeadingText', e.target.value)} placeholder="Product added to cart!" />

The main heading shown at the top of the popup

Display the confirmation icon beside the popup heading

updateSettings('showSuccessIcon', checked)} />
{/* Colors Section — Always Free */} toggleSection('colors')}> Colors
updateStyles('overlayColor', v)} /> updateStyles('overlayOpacity', value)} min={0} max={100} step={5} unit="%" /> updateStyles('textColor', v)} globalTokenId="text" featureDefault="#1f2937" /> updateStyles('headingColor', v)} globalTokenId="text" featureDefault="#111827" /> updateStyles('priceColor', v)} globalTokenId="success" featureDefault="#047857" /> updateStyles('borderColor', v)} fullWidth /> updateStyles('iconColor', v)} globalTokenId="primary" featureDefault="#00226b" /> updateStyles('iconBackgroundColor', v)} globalTokenId="accent" featureDefault="#eef4ff" />
{/* Button Colors Section — Free */} toggleSection('buttons')}> Button Colors
updateStyles('primaryButtonBg', v)} globalTokenId="primary" featureDefault="#00226b" /> updateStyles('primaryButtonText', v)} /> updateStyles('primaryButtonHoverBg', v)} globalTokenId="secondary" featureDefault="#001a52" />
updateStyles('secondaryButtonBg', v)} /> updateStyles('secondaryButtonText', v)} /> updateStyles('secondaryButtonHoverBg', v)} />
{/* Upgrade nudge — plain text for Free users only */} {!isPro && (

For full customization control including typography, spacing, borders, and more, upgrade to Swift Commerce Pro.

)} {/* Background Styling Section — Pro only */} {isPro && ( toggleSection('background')}> Background
updateStyles('backgroundColor', v)} globalTokenId="background" featureDefault="#ffffff" /> updateStyles('productAreaBgColor', v)} />
{styles.productAreaBgColor && ( )}
)} {/* Typography Section — Pro only */} {isPro && ( toggleSection('typography')}> Typography
updateStyles('fontFamily', value)} globalTokenId="body" featureDefault="inherit" />
)} {/* Text Alignment Section — Pro only */} {isPro && ( toggleSection('textAlignment')}> Text Alignment

Controls the alignment of all text elements including heading, product info, prices, and button positioning.

updateStyles('textAlign', value as PopupStyleSettings['textAlign'])} className="flex gap-4" >
)} {/* Spacing & Dimensions Section — Pro only */} {isPro && ( toggleSection('spacing')}> Spacing & Dimensions
updateStyles('popupWidth', value.toString())} min={320} max={800} step={20} /> updateStyles('padding', value.toString())} min={12} max={48} step={4} /> updateStyles('itemSpacing', value.toString())} min={8} max={32} step={4} /> updateStyles('productAreaPadding', value.toString())} min={0} max={32} step={2} /> updateStyles('relatedProductsGap', value.toString())} min={4} max={32} step={2} /> updateStyles('relatedButtonsGap', value.toString())} min={0} max={48} step={2} /> updateStyles('buttonGap', value.toString())} min={0} max={24} step={2} />
)} {/* Border & Shadow Section — Pro only */} {isPro && ( toggleSection('border')}> Border & Shadow
updateStyles('borderWidth', value.toString())} min={0} max={4} step={1} />
updateStyles('productAreaBorderRadius', value.toString())} min={0} max={24} step={2} />

Applies when a product row background or padding is used.

{/* Independent Button Border Radius */}

Controls the roundness of popup buttons independently from the popup container

)} {/* Success Icon Styling Section — Pro only */} {isPro && ( toggleSection('icon')}> Success Icon
updateStyles('iconSize', value.toString())} min={28} max={64} step={2} /> updateStyles('iconBorderRadius', value.toString())} min={0} max={50} step={2} unit="%" />
)} {/* Close Button Styling Section — Pro only */} {isPro && ( toggleSection('closeButton')}> Close Button
updateStyles('closeButtonSize', value.toString())} min={24} max={44} step={2} />
updateStyles('closeButtonColor', v)} featureDefault="#6b7280" /> updateStyles('closeButtonBgColor', v)} featureDefault="transparent" />
)} {/* Animation Section — Pro only */} {isPro && ( toggleSection('animation')}> Animation

Choose an entrance animation for your popup. The animation adapts automatically to each template type.

Default uses each template's native animation — scale for Classic, slide-right for Flyout, slide-up for Solid Bar. Other options override the default with a unified animation style.

)}
{/* Right Column - Sticky Preview */}
) }