import { useState, useEffect } from 'react'; import { Drawer, Button, toast } from '@bsf/force-ui'; import { CheckIcon } from '@heroicons/react/24/outline'; import { __ } from '@wordpress/i18n'; import parse from 'html-react-parser'; import { doApiFetch } from '@Store'; import SkeletonLoader from '@Components/common/skeletons/SkeletonLoader'; import SmsTemplatesDrawerBody from './SmsTemplatesDrawerBody'; const SmsTemplatesDrawer = ( { open, setOpen, template, onSave } ) => { const [ formState, setFormState ] = useState( { template_name: '', sms_body: `Hi {{customer.firstname}}! You left {{cart.product.names}} in your cart. Complete your order before it’s gone: {{cart.checkout_url}}`, sms_frequency: 10, sms_frequency_unit: 'MINUTE', is_activated: false, override_global_coupon: false, discount_type: 'percent', coupon_amount: '', coupon_expiry_date: 1, coupon_expiry_unit: 'days', auto_coupon: false, free_shipping_coupon: false, individual_use_only: false, exclude_product_ids: '', enable_sms_rule_engine: false, sms_rule_engine: [], } ); const [ isSubmitting, setIsSubmitting ] = useState( false ); const [ isLoading, setIsLoading ] = useState( true ); const [ errors, setErrors ] = useState( {} ); useEffect( () => { setIsLoading( true ); if ( template ) { setFormState( { ...template, } ); } else { // Reset form for new template with default values setFormState( { template_name: '', sms_body: `Hi {{customer.firstname}}! You left {{cart.product.names}} in your cart. Complete your order before it’s gone: {{cart.checkout_url}}`, sms_frequency: 10, sms_frequency_unit: 'MINUTE', is_activated: false, override_global_coupon: false, discount_type: 'percent', coupon_amount: '', coupon_expiry_date: 1, coupon_expiry_unit: 'days', auto_coupon: false, free_shipping_coupon: false, individual_use_only: false, exclude_product_ids: '', enable_sms_rule_engine: false, sms_rule_engine: [], } ); } setErrors( {} ); setIsLoading( false ); }, [ template, open ] ); const handleChange = ( name, value ) => { setFormState( ( prev ) => { return { ...prev, [ name ]: value }; } ); // Clear error for this field if it exists if ( errors[ name ] ) { setErrors( { ...errors, [ name ]: null } ); } }; const isEmptyStringOrArray = ( val ) => { return ( ( typeof val === 'string' && val.trim() === '' ) || ( Array.isArray( val ) && val.length === 0 ) ); }; const validateForm = () => { const newErrors = {}; if ( ! formState.template_name.trim() ) { newErrors.template_name = __( 'Template name is required', 'woo-cart-abandonment-recovery' ); } if ( ! formState.sms_body.trim() ) { newErrors.email_body = __( 'SMS body is required', 'woo-cart-abandonment-recovery' ); } if ( formState.email_frequency < 1 ) { newErrors.email_frequency = __( 'Time should be minimum 1 min.', 'woo-cart-abandonment-recovery' ); } if ( formState.sms_body.length > 160 ) { newErrors.sms = __( 'SMS body should be less than 160 characters.', 'woo-cart-abandonment-recovery' ); } if ( ! [ '', '0', false ].includes( formState?.enable_sms_rule_engine ) ) { let rules = formState.sms_rule_engine || []; if ( typeof rules === 'string' ) { try { rules = JSON.parse( rules ); } catch ( e ) { newErrors.sms_rule_engine = __( 'Invalid JSON in rule engine', 'woo-cart-abandonment-recovery' ); return false; } } if ( rules.length === 0 || rules.some( ( group ) => group.rules && group.rules.some( ( rule ) => isEmptyStringOrArray( rule.condition ) || isEmptyStringOrArray( rule.value ) || isEmptyStringOrArray( rule.operator ) ) ) ) { newErrors.sms_rule_engine = __( 'Missing fields in rule: condition, operator, or value.', 'woo-cart-abandonment-recovery' ); } } setErrors( newErrors ); if ( Object.keys( newErrors ).length !== 0 ) { toast.error( 'Error!', { description: parse( Object.values( newErrors ).join( '
' ) ), } ); return false; } return true; }; const handleSubmit = () => { if ( ! validateForm() ) { return; } setIsSubmitting( true ); const formData = new window.FormData(); // Set the full option name in the form data formData.append( 'wcf_template_name', formState.template_name ); formData.append( 'wcf_sms_body', formState.sms_body ); formData.append( 'wcf_sms_frequency', formState.sms_frequency ); formData.append( 'wcf_sms_frequency_unit', formState.sms_frequency_unit ); formData.append( 'wcf_activate_sms_template', formState.is_activated ? '1' : '' ); formData.append( 'wcf_override_global_coupon', formState.override_global_coupon ? '1' : '' ); formData.append( 'wcf_discount_type', formState.discount_type ); formData.append( 'wcf_coupon_amount', formState.coupon_amount ); formData.append( 'wcf_coupon_expiry_date', formState.coupon_expiry_date ); formData.append( 'wcf_coupon_expiry_unit', formState.coupon_expiry_unit ); formData.append( 'wcf_exclude_product_ids', formState.exclude_product_ids ); formData.append( 'wcf_auto_coupon', formState.auto_coupon ? '1' : '' ); formData.append( 'wcf_free_shipping_coupon', formState.free_shipping_coupon ? '1' : '' ); formData.append( 'wcf_individual_use_only', formState.individual_use_only ? '1' : '' ); formData.append( 'wcf_enable_sms_rule_engine', formState?.enable_sms_rule_engine ? '1' : '' ); formData.append( 'wcf_sms_rule_engine', JSON.stringify( formState?.sms_rule_engine || [] ) ); // Add template ID if editing if ( template?.id ) { formData.append( 'id', template.id ); formData.append( 'action', 'wcar_pro_update_sms_template' ); formData.append( 'security', cart_abandonment_admin?.update_sms_template_nonce ); } else { formData.append( 'action', 'wcar_pro_save_sms_template' ); formData.append( 'security', cart_abandonment_admin?.save_sms_template_nonce ); } const ajaxUrl = cart_abandonment_admin?.ajax_url || window.ajaxurl; // Make API call doApiFetch( ajaxUrl, formData, 'POST', ( response ) => { if ( response.success ) { // Call the parent's onSave callback with the updated template onSave( response.data.template ); toast.success( 'Success!', { description: __( 'Template saved successfully', 'woo-cart-abandonment-recovery' ), } ); } else { toast.success( 'Error!', { description: response.data.message || __( 'Failed to save template', 'woo-cart-abandonment-recovery' ), } ); } }, ( error ) => { toast.error( 'Error!', { description: error.message || __( 'Failed to save template', 'woo-cart-abandonment-recovery' ), } ); }, true ).finally( () => { setIsSubmitting( false ); } ); }; const truncateText = ( text, maxLength = 60 ) => { return text.length > maxLength ? text.slice( 0, maxLength ) + '...' : text; }; return ( setOpen( ( prev ) => ! prev ) } transitionDuration={ 0.2 } className="z-[100000]" >
{ isLoading ? ( <>
) : ( <> { truncateText( formState?.template_name ? formState.template_name : 'New SMS Template' ) }
) }
{ isLoading ? (
) : ( <> { errors.submit && (

{ errors.submit }

) } ) }
); }; export default SmsTemplatesDrawer; Horseshoe & Roses 150mm x 170mm - Meadow Place House Signs

Horseshoe & Roses 150mm x 170mm

£65.00

Our stunning number signs are cast in a durable solid resin, unlike cast iron they will not corrode or rust.

Several coats of tough weather resistant acrylic paint are applied to each sign with its raised lettering and traditional edge moulding, resulting in a lasting and beautiful gloss or matt finish.

All plaques are supplied with holes, screws and rawl plugs ready to install.

SKU: N/A Categories: , Tag: