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; Home - Meadow Place House Signs

Welcome to Meadow Place Signs
51 years of creative sign making

Beautiful, unique, tough weather resistant name
signs and
numbers,
handmade and
delivered to your door within 28 days

 

Shop Now

Cast House Signs & Numbers

Cast in solid, reinforced resin our house signs are tough and will not rust or corrode.
Each sign is sprayed with several coats of durable weather-resistant acrylic, resulting in a beautiful lasting gloss or Matt finish. All lettering, numbers, flourishes and sculptures are cast in relief creating an impressive substantial and stylish sign.

 

Shop Our Signs

Made to your
requirements

Most of our house signs can be adapted. For example, we can change the colours and combine flourishes. So get in touch with us today to discuss how we can work with you
to create your bespoke handmade house signs.

 

Contact Us

Gift Cards Now Available

Meadow Place Gift Cards are now available to purchase, follow the link below to find out more!

 

Shop Now

Stunning Handmade Sculptures

Our finely detailed sculptures are meticulously finished by hand in full colour.

All our products are handmade in the UK