Woocommerce blocks: Show custom field based of selected shipping method

35 Views Asked by At

Maybe someone can help with showing a custom field depending on the selected shipping method in the new block-based WP WooCommerce Checkout page?

Example

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>
    );
};
1

There are 1 best solutions below

0
markak On BEST ANSWER

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>
    );
};