import { __ } from '@wordpress/i18n'; import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { Alert, Card, ChoiceGroup, Input, Page, Spinner, Toggle, } from './UI/index.jsx'; import { api } from '../api/index.js'; import { ShoppingCart } from 'lucide-react'; import { decodeHtmlEntities } from '../lib/utils.js'; const PREVIEW_THEMES = [ { value: 'light', label: __( 'Light Surface', 'arrayfunnel' ), }, { value: 'graphite', label: __( 'Graphite Surface', 'arrayfunnel' ), }, ]; const PREVIEW_RADIUS = [ { value: 'soft', label: __( 'Soft', 'arrayfunnel' ), }, { value: 'balanced', label: __( 'Balanced', 'arrayfunnel' ), }, { value: 'expressive', label: __( 'Expressive', 'arrayfunnel' ), }, ]; const PREVIEW_ACCENTS = [ { value: 'emerald', label: __( 'Emerald', 'arrayfunnel' ), swatch: '#059669', previewClass: 'bg-emerald-600', }, { value: 'black', label: __( 'Black', 'arrayfunnel' ), swatch: '#0f172a', previewClass: 'bg-slate-900', }, { value: 'sky', label: __( 'Sky', 'arrayfunnel' ), swatch: '#0284c7', previewClass: 'bg-sky-600', }, ]; const currencySymbol = decodeHtmlEntities( window.arrayfunnelAdmin?.currency?.symbol || '$' ); const DEFAULT_PRESETS = { arrayfunnel_side_cart_theme: 'light', arrayfunnel_side_cart_radius: 'balanced', arrayfunnel_side_cart_accent: 'emerald', arrayfunnel_side_cart_open_mode: 'always', }; function normalizeSettings( settings = {} ) { const theme = PREVIEW_THEMES.some( ( item ) => item.value === settings.arrayfunnel_side_cart_theme ) ? settings.arrayfunnel_side_cart_theme : DEFAULT_PRESETS.arrayfunnel_side_cart_theme; const radius = PREVIEW_RADIUS.some( ( item ) => item.value === settings.arrayfunnel_side_cart_radius ) ? settings.arrayfunnel_side_cart_radius : DEFAULT_PRESETS.arrayfunnel_side_cart_radius; const accent = PREVIEW_ACCENTS.some( ( item ) => item.value === settings.arrayfunnel_side_cart_accent ) ? settings.arrayfunnel_side_cart_accent : DEFAULT_PRESETS.arrayfunnel_side_cart_accent; const openMode = settings.arrayfunnel_side_cart_open_mode === 'smart' ? 'smart' : DEFAULT_PRESETS.arrayfunnel_side_cart_open_mode; return { ...settings, arrayfunnel_side_cart_theme: theme, arrayfunnel_side_cart_radius: radius, arrayfunnel_side_cart_accent: accent, arrayfunnel_side_cart_open_mode: openMode, }; } export default function SideCartEditor() { const pageHeader = { title: __( 'Side Cart', 'arrayfunnel' ), subtitle: __( 'Visual customization + behavior controls with real-time preview', 'arrayfunnel' ), }; const qc = useQueryClient(); const [ settings, setSettings ] = useState( null ); const [ original, setOriginal ] = useState( null ); const { data: settingsData, isLoading } = useQuery( { queryKey: [ 'settings' ], queryFn: api.getSettings, staleTime: 30_000, gcTime: 5 * 60_000, } ); useEffect( () => { if ( ! settingsData ) { return; } const normalized = normalizeSettings( settingsData ); setSettings( normalized ); setOriginal( JSON.stringify( normalized ) ); }, [ settingsData ] ); const { mutateAsync: save, isPending: savingSettings } = useMutation( { mutationFn: ( { changes } ) => api.saveSettings( changes ), onSuccess( response, { changes, snapshot } ) { const saved = { ...snapshot, ...( response?.saved || {} ) }; setOriginal( JSON.stringify( saved ) ); qc.setQueryData( [ 'settings' ], ( current ) => ( { ...current, ...changes, ...( response?.saved || {} ), } ) ); }, } ); const hasChanges = settings && JSON.stringify( settings ) !== original; useEffect( () => { if ( typeof window === 'undefined' ) { return; } window.dispatchEvent( new window.CustomEvent( 'arrayfunnel:dirty-state', { detail: { dirty: Boolean( hasChanges ), }, } ) ); return () => { window.dispatchEvent( new window.CustomEvent( 'arrayfunnel:dirty-state', { detail: { dirty: false, }, } ) ); }; }, [ hasChanges ] ); const set = ( key, val ) => setSettings( ( s ) => ( { ...s, [ key ]: val, } ) ); useEffect( () => { const handleDiscard = () => { if ( ! savingSettings && original !== null ) { setSettings( JSON.parse( original ) ); } }; window.addEventListener( 'arrayfunnel:discard-current-page', handleDiscard ); return () => window.removeEventListener( 'arrayfunnel:discard-current-page', handleDiscard ); }, [ original, savingSettings ] ); const saveCurrentPage = useCallback( async () => { if ( ! hasChanges || savingSettings ) { return; } const baseline = JSON.parse( original ); const changes = Object.fromEntries( Object.entries( settings ).filter( ( [ key, value ] ) => JSON.stringify( value ) !== JSON.stringify( baseline[ key ] ) ) ); await save( { changes, snapshot: settings } ); }, [ hasChanges, original, save, savingSettings, settings ] ); useEffect( () => { const handleHeaderSave = ( event ) => { if ( ! hasChanges ) { return; } const task = saveCurrentPage(); event?.detail?.register?.( task ); }; window.addEventListener( 'arrayfunnel:save-current-page', handleHeaderSave ); return () => window.removeEventListener( 'arrayfunnel:save-current-page', handleHeaderSave ); }, [ hasChanges, saveCurrentPage ] ); const theme = settings?.arrayfunnel_side_cart_theme || DEFAULT_PRESETS.arrayfunnel_side_cart_theme; const radius = settings?.arrayfunnel_side_cart_radius || DEFAULT_PRESETS.arrayfunnel_side_cart_radius; const accent = settings?.arrayfunnel_side_cart_accent || DEFAULT_PRESETS.arrayfunnel_side_cart_accent; const previewTone = useMemo( () => { return theme === 'graphite' ? 'bg-slate-900 text-slate-100 ring-slate-700' : 'bg-white text-slate-900 ring-slate-200'; }, [ theme ] ); const previewRadius = useMemo( () => { const classes = { soft: 'rounded-md', balanced: 'rounded-xl', expressive: 'rounded-2xl', }; return classes[ radius ] || classes.balanced; }, [ radius ] ); const previewAccent = useMemo( () => { const found = PREVIEW_ACCENTS.find( ( item ) => item.value === accent ); return found ? found.previewClass : 'bg-emerald-600'; }, [ accent ] ); if ( isLoading || ! settings ) { return (
); } return (
set( 'arrayfunnel_side_cart_enabled', v ? 'yes' : 'no' ) } label={ __( 'Enable Side Cart', 'arrayfunnel' ) } description={ __( 'Replace cart redirect with a right-side drawer experience.', 'arrayfunnel' ) } /> set( 'arrayfunnel_side_cart_free_shipping', v ) } placeholder={ __( '50', 'arrayfunnel' ) } type="number" prefix={ currencySymbol } description={ __( 'Leave empty to hide the progress banner.', 'arrayfunnel' ) } /> { Number( settings.arrayfunnel_side_cart_free_shipping || 0 ) > 0 && ( { __( 'Free shipping progress will update automatically from cart totals.', 'arrayfunnel' ) } ) } set( 'arrayfunnel_side_cart_open_mode', value ) } columns={ 2 } options={ [ { value: 'smart', label: __( 'Smart (Recommended)', 'arrayfunnel' ), description: __( 'First add opens the cart. After you close it, later adds only update the counter.', 'arrayfunnel' ), }, { value: 'always', label: __( 'Always Open', 'arrayfunnel' ), description: __( 'Every successful add-to-cart opens the drawer.', 'arrayfunnel' ), }, ] } />
set( 'arrayfunnel_side_cart_theme', value ) } options={ PREVIEW_THEMES } columns={ 2 } /> set( 'arrayfunnel_side_cart_radius', value ) } options={ PREVIEW_RADIUS } /> set( 'arrayfunnel_side_cart_accent', value ) } options={ PREVIEW_ACCENTS } />

{ __( 'Your Cart', 'arrayfunnel' ) }

{ __( '3', 'arrayfunnel' ) }

{ __( 'Drawer preview on mobile viewport', 'arrayfunnel' ) }

{ __( 'Subtotal', 'arrayfunnel' ) } { __( '$40.00', 'arrayfunnel' ) }

{ __( 'Preview updates instantly as you adjust visual settings.', 'arrayfunnel' ) }

); } function PreviewItem( { title, price } ) { return (

{ title }

{ price }

); }