Maybe someone can help with showing a custom field depending on the selected shipping method in the new block-based WP WooCommerce Checkout page?
Do I have to add something in the block.js file or do it need to be done via plain javascript? I can't find any examples or explanations in the documentation or in google.
block.js
/**
* External dependencies
*/
import { useEffect, useState, useCallback } from '@wordpress/element';
import { SelectControl, TextareaControl } from '@wordpress/components';
import { useSelect, useDispatch } from '@wordpress/data';
import { debounce } from 'lodash';
/**
* Internal dependencies
*/
import { options } from './options';
import { txt } from './text';
export const Block = ({ checkoutExtensionData, extensions }) => {
const { setExtensionData } = checkoutExtensionData;
const debouncedSetExtensionData = useCallback(
debounce((namespace, key, value) => {
setExtensionData(namespace, key, value);
}, 1000),
[setExtensionData]
);
const terminalValidationErrorId = 'terminal';
const { setValidationErrors, clearValidationError } = useDispatch(
'wc/store/validation'
);
const validationError = useSelect((select) => {
const store = select('wc/store/validation');
return store.getValidationError(terminalValidationErrorId);
});
const [
selectedTerminal,
setSelectedTerminal,
] = useState('');
/* Handle changing the select's value */
useEffect(() => {
setExtensionData(
'terminals',
'alternateShippingInstruction',
selectedTerminal
);
if ( selectedTerminal !== '' ) {
clearValidationError(terminalValidationErrorId);
return;
}
if ( selectedTerminal === '' ) {
setValidationErrors({
[terminalValidationErrorId]: {
message: txt.error_terminal,
hidden: false
}
});
}
}, [
setExtensionData,
selectedTerminal,
setValidationErrors,
clearValidationError,
]);
return (
<div className="terminal_select_container">
<SelectControl
label={txt.title_terminal}
value={selectedTerminal}
options={options}
onChange={setSelectedTerminal}
/>
{(validationError?.hidden || selectedTerminal !== '') ? null : (
<div className="wc-block-components-validation-error terminal-error">
<span>{validationError?.message}</span>
</div>
)}
</div>
);
};
I found a solution myself.
export const Block = ({ checkoutExtensionData, extensions }) => {
const [showBlock, setShowBlock] = useState(false);
const shippingRates = useSelect((select) => {
const store = select('wc/store/cart');
return store.getCartData().shippingRates;
});
const getActiveShippingRates = (shippingRates) => {
if ( ! shippingRates.length ) {
return [];
}
let activeRates = [];
for ( let i = 0; i < shippingRates.length; i++ ) {
if ( ! shippingRates[i].shipping_rates ) {
continue;
}
for ( let j = 0; j < shippingRates[i].shipping_rates.length; j++ ) {
activeRates.push(shippingRates[i].shipping_rates[j]);
}
}
return activeRates;
};
const getMyPluginData = () => {
if ( ! wcSettings || ! wcSettings["myplugin-blocks_data"] ) {
return [];
}
return wcSettings["myplugin-blocks_data"];
};
const isMyShippingRate = (methodKey) => {
for ( let [key, value] of Object.entries(getMyPluginData().methods) ) {
if ( methodKey == value ) {
return true;
}
}
return false;
};
useEffect(() => {
setShowBlock(false);
if ( shippingRates.length ) {
const activeRates = getActiveShippingRates(shippingRates);
for ( let i = 0; i < activeRates.length; i++ ) {
if ( ! activeRates[i].rate_id ) {
continue;
}
if ( isMyShippingRate(activeRates[i].rate_id) && activeRates[i].selected ) {
setShowBlock(true);
}
}
}
}, [
shippingRates
]);
if ( ! showBlock ) {
return <></>
}
return (
<div>
...
</div>
);
};