File "button-data-context.js"

Full Path: /home/siazco/grocery.siazco.se/wp-content/plugins/yith-woocommerce-wishlist/assets/js/src/utils/button-data-context.js
File size: 8.55 KB
MIME-type: text/x-java
Charset: utf-8

/* globals yithWcwlAddToWishlist */

import React, { useContext, useState, useRef, useEffect } from 'react';
import { ThemeProvider } from '@lapilli-ui/styles';
import { createContext, useContextSelector } from 'use-context-selector';
import useProductData from '../components/add-to-wishlist/hooks/use-product-data';
import { useDispatch } from 'react-redux';
import { addProductToWishlist, removeProductFromWishlist } from '../features/products-data/products-data-actions';
import classNames from 'classnames';
import { ComponentsExtensionProvider } from './index'
import useFeedback from '../components/add-to-wishlist/hooks/use-feedback';

const ButtonDataContext = createContext( {} );

export const useButtonAttributes = ( mergeWithGlobalOptions = true ) => mergeWithGlobalOptions ? { ...yithWcwlAddToWishlist.globalOptions, ...(useContext( ButtonDataContext ).attributes) } : useContext( ButtonDataContext ).attributes;
export const useButtonData = () => useContextSelector( ButtonDataContext, v => v );
export const useButtonStyle = () => {
	return useContextSelector( ButtonDataContext, ( v ) => v?.style );
}
export const useAddToWishlistButtonData = () => useContextSelector(
	ButtonDataContext, ( { href, icon, buttonRef: ref, className, onButtonClick: onClick, label } ) => {
		return {
			label,
			href,
			icon,
			ref,
			className,
			onClick
		}
	}
);
export const useButtonTooltipData = () => useContextSelector(
	ButtonDataContext,
	( state ) => {
		return {
			hasDataLoaded: state?.hasDataLoaded,
			add_label: state?.add_label,
			remove_label: state?.remove_label,
			browse_label: state?.browse_label,
			move_label: state?.move_label,

			isAdded: state?.isAdded,
			behaviour: state?.behaviour,
			buttonRef: state?.buttonRef,
			isDropdownOpen: state?.isDropdownOpen,
			tooltipEnabled: state?.tooltipEnabled,
		}
	}
)
export const useButtonDropdownData = () => useContextSelector(
	ButtonDataContext,
	( state ) => {
		return {
			buttonRef: state?.buttonRef,
			availableLists: state?.availableLists,
			isDropdownOpen: state?.isDropdownOpen,
			handleCloseDropdown: state?.handleCloseDropdown,
			wishlists: state?.wishlists,
		}
	}
)


export const ButtonDataProvider = ( { children, attributes, dataExtensions, componentsExtensions } ) => {
	const [ isPerformingAction, setIsPerformingAction ] = useState( false );
	const richAttributes = { ...yithWcwlAddToWishlist.globalOptions, ...attributes };

	const {
		buttonId,
		productId: productIdAttribute,
		style,
		isOverProductImage,

		add_label,
		added_label,
		remove_label,
		browse_label,

		icon,
		icon_type,
		custom_icon,

		added_icon: added_icon_attribute,
		added_icon_type,
		custom_added_icon,

		is_single,
		loop_position,
		button_over_image_style,
		position_over_image_in_loop,
		behaviour: attribute_behaviour,
	} = richAttributes;

	const [ productId, setProductId ] = useState( productIdAttribute )

	const {
		isAdded,
		isLoading,
		alreadyIn,
		productData,
		hasDataLoaded,
	} = useProductData( productId, attributes );

	const {
		feedbackType,
		showFeedback,
		feedbackMessage,
		feedbackDuration,
		setFeedbackType,
		setShowFeedback,
		setFeedbackMessage,
		setFeedbackDuration,
		addFeedback,
		clearFeedback,
		feedbackAnimation,
		setFeedbackAnimation,
	} = useFeedback( productId, richAttributes, isPerformingAction );

	const buttonRef = useRef();
	const dispatch = useDispatch();
	const add_icon = (() => {
		if ( 'custom' === icon_type ) {
			return custom_icon;
		}

		return icon;
	})();
	const added_icon = (() => {
		if ( added_icon_type === 'same' ) {
			return add_icon;
		}

		if ( 'custom' === added_icon_type ) {
			return custom_added_icon;
		}

		return added_icon_attribute;
	})();
	const iconToDisplay = isAdded ? added_icon : add_icon;

	const behaviour = (() => {
		if ( ! yithWcwlAddToWishlist.isUserLoggedIn && 'yes' === yithWcwlAddToWishlist.globalOptions.wishlist_disabled_for_unauthenticated_users ) {
			return 'view';
		}
		return [ 'add', 'remove' ].includes( attribute_behaviour ) ? attribute_behaviour : 'view'
	})();
	const href = (() => {
		if ( ! yithWcwlAddToWishlist.isUserLoggedIn && 'yes' === yithWcwlAddToWishlist.globalOptions.wishlist_disabled_for_unauthenticated_users ) {
			return yithWcwlAddToWishlist.login_wishlist_url.replace( '%product_id%', productId );
		}
		return 'view' === behaviour && isAdded ? yithWcwlAddToWishlist.wishlist_url : null
	})();

	const handleActionCallback = callback => () => {
		setIsPerformingAction( false );
		jQuery( document ).trigger( 'yith_wcwl_reload_fragments', { firstLoad: false, avoidDataInvalidation: true } );
		'function' === typeof callback && callback();
	}
	const handleButtonAction = ( action, callback ) => {
		if ( 'function' === typeof action ) {
			setIsPerformingAction( true )
			action().then( handleActionCallback( callback ) )
		}
	}
	const handleAddToWishlist = ( callback ) => handleButtonAction( async () => {
		await dispatch( addProductToWishlist( productId ) );
	}, callback );
	const handleRemoveFromWishlist = ( callback ) => handleButtonAction( async () => {
		await dispatch( removeProductFromWishlist( productId ) );
	}, callback );
	const onButtonClick = ( event) => {
		if ( href ) return false;
		event?.preventDefault();
		event?.stopPropagation();
		if ( ! hasDataLoaded || isLoading ) return false;

		if ( isAdded && behaviour !== 'add' ) {
			if ( behaviour === 'remove' ) {
				handleRemoveFromWishlist();
			} else {
				window.location = yithWcwlAddToWishlist.wishlist_url
			}
		} else {
			handleAddToWishlist();
		}
	}

	const getStyle = () => {
		if ( ! is_single && loop_position === 'before_image' && isOverProductImage ) return 'icon-button';
		if ( style === 'link' ) return 'anchor';
		return style === 'button_default' ? 'themed-button' : 'custom-button';
	}
	const getLabel = () => {
		if ( isAdded ) {
			if ( behaviour === 'add' && ! alreadyIn ) return added_label;
			if ( behaviour === 'remove' ) return remove_label;
			if ( behaviour === 'view' ) return browse_label;
		}
		return add_label;
	}

	const getClasses = () => classNames( {
		'yith-wcwl-add-to-wishlist-button': true,
		[ `yith-wcwl-add-to-wishlist-button--${ getStyle() }` ]: true,
		'yith-wcwl-add-to-wishlist-button--loading': isLoading,
		'yith-wcwl-add-to-wishlist-button--first-loading': isLoading && productData?.isAdded === undefined,
		'yith-wcwl-add-to-wishlist-button--added': isAdded,
		'yith-wcwl-add-to-wishlist-button--single': is_single,
		'yith-wcwl-add-to-wishlist-button-over-image': isOverProductImage,
		[ `yith-wcwl-add-to-wishlist-button-over-image--${ position_over_image_in_loop || 'top-left' }` ]: isOverProductImage && loop_position === 'before_image',
		'yith-wcwl-add-to-wishlist-button-over-image--hover': isOverProductImage && loop_position === 'before_image' && button_over_image_style === 'hover' && ! isAdded,
		[ yithWcwlAddToWishlist?.buttonClasses + ' yith-wcwl-theme-button-style' ]: getStyle() === 'themed-button',
	} );

	useEffect( () => {
		if ( is_single ) {
			const handleFoundVariation = ( e, variation ) => {
				const form = e.target;
				const parentId = form?.getAttribute( 'data-product_id' )
				if ( parentId === attributes?.productId ) {
					setProductId( variation.variation_id )
				}
			};
			const handleResetVariation = () => setProductId( productIdAttribute );

			jQuery( document ).on( 'found_variation', handleFoundVariation );
			jQuery( document ).on( 'reset_data', handleResetVariation );

			return () => {
				jQuery( document ).off( 'found_variation', handleFoundVariation );
				jQuery( document ).off( 'reset_data', handleResetVariation );
			}
		}
	}, [] );

	let value = {
		buttonId,
		productId,
		attributes,
		productData,
		hasDataLoaded,
		richAttributes,
		isOverProductImage,

		isPerformingAction,
		setIsPerformingAction,

		icon: iconToDisplay,
		added_icon,
		add_icon,

		add_label,
		added_label,
		remove_label,
		browse_label,

		href,
		isAdded,
		is_single,
		isLoading,
		buttonRef,
		behaviour,
		style: getStyle(),
		label: getLabel(),
		className: getClasses(),

		feedbackType,
		showFeedback,
		feedbackMessage,
		feedbackDuration,
		feedbackAnimation,

		setFeedbackType,
		setShowFeedback,
		setFeedbackMessage,
		setFeedbackDuration,
		setFeedbackAnimation,

		addFeedback,
		clearFeedback,

		onButtonClick,
		handleButtonAction,
		handleAddToWishlist,
		handleRemoveFromWishlist,
	}

	if ( 'function' === typeof dataExtensions ) {
		value = {
			...value,
			...dataExtensions( value )
		}
	}

	return <ButtonDataContext.Provider value={ value }>
		<ComponentsExtensionProvider extensions={ componentsExtensions }>
			<ThemeProvider>
				{ children }
			</ThemeProvider>
		</ComponentsExtensionProvider>
	</ButtonDataContext.Provider>
};