| 1 |
/** |
| 2 |
* Edit component for the Payment Form block. |
| 3 |
* |
| 4 |
* This component renders the block in the editor and provides |
| 5 |
* the editing interface for block attributes. |
| 6 |
* |
| 7 |
* @package Better_Payment |
| 8 |
* @since 1.0.0 |
| 9 |
*/ |
| 10 |
|
| 11 |
import { __ } from '@wordpress/i18n'; |
| 12 |
import { useBlockProps, InspectorControls } from '@wordpress/block-editor'; |
| 13 |
import classnames from 'classnames'; |
| 14 |
import { useEffect, memo } from '@wordpress/element'; |
| 15 |
import { useSelect } from '@wordpress/data'; |
| 16 |
import apiFetch from '@wordpress/api-fetch'; |
| 17 |
// Import the inspector controls |
| 18 |
import Inspector from './inspector'; |
| 19 |
import Layout1 from './layouts/layout-1'; |
| 20 |
import Layout2 from './layouts/layout-2'; |
| 21 |
import Layout3 from './layouts/layout-3'; |
| 22 |
import { mapSettingsToAttributes } from '../helpers/helpers'; |
| 23 |
import Style from './style'; |
| 24 |
import defaultAttributes from "./attributes"; |
| 25 |
import { BlockProps, withBlockContext } from '@better-payment/controls'; |
| 26 |
/** |
| 27 |
* Edit component. |
| 28 |
* |
| 29 |
* @param {Object} props Block props. |
| 30 |
* @param {Object} props.attributes Block attributes. |
| 31 |
* @param {Function} props.setAttributes Function to set block attributes. |
| 32 |
* @param {boolean} props.isSelected Whether the block is selected. |
| 33 |
* @returns {JSX.Element} The edit component. |
| 34 |
*/ |
| 35 |
function Edit(props) { |
| 36 |
const { attributes, setAttributes, isSelected, clientId } = props; |
| 37 |
const { initialSettingsApplied, formLayout, blockId } = attributes; |
| 38 |
|
| 39 |
useEffect(() => { |
| 40 |
if ( ! blockId ) { |
| 41 |
setAttributes( { blockId: clientId } ); |
| 42 |
} |
| 43 |
if (initialSettingsApplied) { |
| 44 |
return; |
| 45 |
} |
| 46 |
const settings = window?.betterPaymentBlockData?.betterPaymentSettings; |
| 47 |
// Only apply settings if they exist; otherwise rely on default attributes |
| 48 |
const attributesFromSettings = settings ? mapSettingsToAttributes(settings) : {}; |
| 49 |
setAttributes({ ...attributes, ...attributesFromSettings, initialSettingsApplied: true }); |
| 50 |
}, []); |
| 51 |
|
| 52 |
// Fetch product data when payment source or product ID changes |
| 53 |
const { paymentSource, woocommerceProductId, fluentcartProductId, stripeDefaultPriceId } = attributes; |
| 54 |
|
| 55 |
useEffect(() => { |
| 56 |
if (paymentSource === 'woocommerce' && woocommerceProductId) { |
| 57 |
const productId = parseInt(woocommerceProductId, 10); |
| 58 |
if (productId > 0) { |
| 59 |
apiFetch({ path: `/wc/v3/products/${productId}` }) |
| 60 |
.then((product) => { |
| 61 |
if (product) { |
| 62 |
setAttributes({ |
| 63 |
productName: product.name || '', |
| 64 |
productPrice: product.price || '', |
| 65 |
productPermalink: product.permalink || '', |
| 66 |
}); |
| 67 |
} |
| 68 |
}) |
| 69 |
.catch(() => { |
| 70 |
// Product not found or WooCommerce REST API not available |
| 71 |
}); |
| 72 |
} |
| 73 |
} else if (paymentSource === 'fluentcart' && fluentcartProductId) { |
| 74 |
const productId = parseInt(fluentcartProductId, 10); |
| 75 |
if (productId > 0) { |
| 76 |
apiFetch({ path: `/better-payment/v1/fluentcart-product/${productId}` }) |
| 77 |
.then((product) => { |
| 78 |
if (product) { |
| 79 |
setAttributes({ |
| 80 |
productName: product.name || '', |
| 81 |
productPrice: product.price || '', |
| 82 |
productPermalink: product.permalink || '', |
| 83 |
}); |
| 84 |
} |
| 85 |
}) |
| 86 |
.catch(() => { |
| 87 |
// Product not found or FluentCart REST API not available |
| 88 |
}); |
| 89 |
} |
| 90 |
} else if (paymentSource === 'stripe' && stripeDefaultPriceId) { |
| 91 |
// Validate Stripe Price ID format (should start with 'price_') |
| 92 |
if (stripeDefaultPriceId.startsWith('price_')) { |
| 93 |
apiFetch({ path: `/better-payment/v1/stripe-price?price_id=${encodeURIComponent(stripeDefaultPriceId)}` }) |
| 94 |
.then((result) => { |
| 95 |
if (result && result.success) { |
| 96 |
setAttributes({ |
| 97 |
productName: result.product_name || '', |
| 98 |
productPrice: String(result.amount) || '', |
| 99 |
productPermalink: '', |
| 100 |
}); |
| 101 |
} |
| 102 |
}) |
| 103 |
.catch(() => { |
| 104 |
// Stripe API error or price not found |
| 105 |
}); |
| 106 |
} |
| 107 |
} else if (paymentSource !== 'woocommerce' && paymentSource !== 'fluentcart' && paymentSource !== 'stripe') { |
| 108 |
// Clear product data when switching away from product-based payment sources |
| 109 |
if (attributes.productName || attributes.productPrice || attributes.productPermalink) { |
| 110 |
setAttributes({ |
| 111 |
productName: '', |
| 112 |
productPrice: '', |
| 113 |
productPermalink: '', |
| 114 |
}); |
| 115 |
} |
| 116 |
} |
| 117 |
}, [paymentSource, woocommerceProductId, fluentcartProductId, stripeDefaultPriceId]); |
| 118 |
|
| 119 |
const postId = useSelect( ( select ) => { |
| 120 |
return select( 'core/editor' ).getCurrentPostId(); |
| 121 |
}, [] ); |
| 122 |
|
| 123 |
const serialized = JSON.stringify({ |
| 124 |
page_id: postId, |
| 125 |
widget_id: attributes.blockId || clientId |
| 126 |
}); |
| 127 |
|
| 128 |
// Build block props with custom classes |
| 129 |
const blockProps = useBlockProps({ |
| 130 |
className: classnames('better-payment-block', `bp-form-${formLayout}`), |
| 131 |
}); |
| 132 |
|
| 133 |
// you must declare this variable |
| 134 |
const enhancedProps = { |
| 135 |
...props, |
| 136 |
style: <Style {...props} /> |
| 137 |
}; |
| 138 |
|
| 139 |
return ( |
| 140 |
<> |
| 141 |
{isSelected && |
| 142 |
<InspectorControls> |
| 143 |
<Inspector |
| 144 |
attributes={attributes} |
| 145 |
setAttributes={setAttributes} |
| 146 |
/> |
| 147 |
</InspectorControls> |
| 148 |
} |
| 149 |
<BlockProps.Edit {...enhancedProps}> |
| 150 |
<div {...blockProps}> |
| 151 |
{(formLayout === 'layout-1') && <Layout1 attributes={attributes} setAttributes={setAttributes} serialized={serialized} pageId={postId} />} |
| 152 |
{(formLayout === 'layout-2') && <Layout2 attributes={attributes} setAttributes={setAttributes} serialized={serialized} pageId={postId} />} |
| 153 |
{(formLayout === 'layout-3') && <Layout3 attributes={attributes} setAttributes={setAttributes} serialized={serialized} pageId={postId} />} |
| 154 |
</div> |
| 155 |
</BlockProps.Edit> |
| 156 |
</> |
| 157 |
); |
| 158 |
} |
| 159 |
export default memo(withBlockContext(defaultAttributes)(Edit)); |