File "features.js"

Full Path: /home/fresvfqn/waterdamagerestorationandrepairsmithtown.com/wp-content/plugins/astra-sites/inc/lib/onboarding/assets/src/steps/features/features.js
File size: 11.25 KB
MIME-type: text/x-java
Charset: utf-8

import { __ } from '@wordpress/i18n';
import { useEffect, useMemo, useState } from 'react';
import { useStateValue } from '../../store/store';
const { imageDir } = starterTemplates;
import {
	FunnelIcon,
	HeartIcon,
	PlayCircleIcon,
	SquaresPlusIcon,
	CheckIcon,
	ChatBubbleLeftEllipsisIcon,
	WrenchIcon,
	PaintBrushIcon,
	Squares2X2Icon,
	QueueListIcon,
	ShoppingCartIcon,
	ArrowLongRightIcon,
	ChevronUpIcon,
	EnvelopeIcon,
	CalendarIcon,
	ArrowTrendingUpIcon,
} from '@heroicons/react/24/outline';
import { classNames } from '../../utils/functions';
import {
	checkRequiredPlugins,
	getFeaturePluginList,
} from '../import-site/import-utils';
import Container from './container';
import Button from './button';
import Dropdown from './dropdown';
import RequiredPlugins from './RequiredPlugins';

const ICON_SET = {
	heart: HeartIcon,
	'squares-plus': SquaresPlusIcon,
	funnel: FunnelIcon,
	'play-circle': PlayCircleIcon,
	'live-chat': ChatBubbleLeftEllipsisIcon,
	'page-builder': PaintBrushIcon,
	'contact-form': QueueListIcon,
	blog: Squares2X2Icon,
	ecommerce: ShoppingCartIcon,
	envelope: EnvelopeIcon,
	calendar: CalendarIcon,
	'arrow-trending-up': ArrowTrendingUpIcon,
};

const getPluginProps = ( id ) => {
	switch ( id ) {
		case 'surecart':
			return {
				icon: (
					<img
						src={ `${ imageDir }surecart-icon.svg` }
						alt="SureCart"
						className="w-5 h-5"
					/>
				),
				title: 'SureCart',
			};
		case 'woocommerce':
			return {
				icon: (
					<img
						src={ `${ imageDir }woocommerce-icon.svg` }
						alt="WooCommerce"
						className="w-5 h-5"
					/>
				),
				title: 'WooCommerce',
			};
		default:
			return {
				icon: <ShoppingCartIcon className="w-5 h-5" />,
				title: 'Ecommerce',
			};
	}
};
const EcommerceOptions = ( {
	ecomSupported,
	selectedEcom,
	onChange,
	disabled,
	dispatch,
} ) => {
	const [ open, setOpen ] = useState( false );

	const handleDropdownClick = ( event ) => {
		if ( disabled ) {
			return;
		}
		event.stopPropagation();
		setOpen( ! open );
	};

	const handleOptionClick = ( id, event ) => {
		if ( disabled ) {
			return;
		}
		event.stopPropagation();
		onChange( id );
		dispatch( {
			type: 'set',
			selectedEcommercePlugin: id,
		} );
		setOpen( false );
	};

	return (
		<div className="bg-[#F6FAFE] z-50 py-1 px-2 shadow-sm rounded-md items-center justify-center w-fit">
			<Dropdown
				width="w-36"
				trigger={
					<div
						className="flex items-center cursor-pointer gap-1.5"
						onClick={ handleDropdownClick }
					>
						<div className="flex items-center">
							{ getPluginProps( selectedEcom ).icon }
							<div className="ml-2">
								<p className="!text-xs leading-3 text-app-text">
									{ getPluginProps( selectedEcom ).title }
								</p>
							</div>
						</div>
						{ ! disabled && (
							<ChevronUpIcon
								className={ classNames(
									'w-3 h-3 text-app-active-icon',
									open ? 'transform rotate-180' : ''
								) }
							/>
						) }
					</div>
				}
				onOpenChange={ setOpen }
				disabled={ disabled }
			>
				{ ! disabled && (
					<div className="py-0.5 px-2 mx-auto bg-white rounded-md">
						{ ecomSupported.map( ( id, index ) => {
							const { icon, title } = getPluginProps( id );
							return (
								<Dropdown.Item
									key={ index }
									onClick={ ( event ) =>
										handleOptionClick( id, event )
									}
									className={ classNames(
										'flex items-center px-2 py-1 rounded-md cursor-pointer',
										'hover:bg-container-background hover:bg-opacity-100'
									) }
								>
									<div className="flex items-center">
										{ icon }
										<div className="ml-2">
											<p className="!text-xs leading-5 text-app-text">
												{ title }
											</p>
										</div>
									</div>
								</Dropdown.Item>
							);
						} ) }
					</div>
				) }
			</Dropdown>
		</div>
	);
};

const ClassicFeatures = () => {
	const [
		{
			siteFeatures,
			currentIndex,
			selectedTemplateID,
			isEcommerce,
			selectedEcommercePlugin,
			templateResponse,
		},
		dispatch,
	] = useStateValue();
	const storedState = useStateValue();
	const [ selectedEcom, setSelectedEcom ] = useState();
	const [ ecomSupported, setEcomSupported ] = useState( [
		'surecart',
		'woocommerce',
	] );

	// Template required plugins list.
	const templateRequiredPluginsList = useMemo( () => {
		return ( templateResponse?.[ 'required-plugins' ] ?? [] )?.map(
			( plugin ) => ( {
				...plugin,
				compulsory: true,
			} )
		);
	}, [ templateResponse ] );

	useEffect( () => {
		if ( isEcommerce ) {
			const allSlugs =
				templateRequiredPluginsList?.map( ( plugin ) => plugin.slug ) ||
				[];

			setEcomSupported( [ 'surecart', 'woocommerce' ] );

			if ( ! selectedEcom || selectedEcom !== selectedEcommercePlugin ) {
				if ( allSlugs?.includes( 'surecart' ) ) {
					setSelectedEcom( 'surecart' );
				} else {
					setSelectedEcom( 'woocommerce' ); // Default to WooCommerce if surecart is not found
				}
			}

			const updatedFeatures = siteFeatures.map( ( feature ) => {
				if ( feature.id === 'ecommerce' ) {
					return { ...feature, compulsory: true, enabled: true };
				}
				return feature;
			} );
			dispatch( {
				type: 'set',
				siteFeatures: updatedFeatures,
			} );
		} else {
			setEcomSupported( [ 'surecart', 'woocommerce' ] );
			setSelectedEcom( selectedEcom || 'surecart' ); // Default to 'surecart'

			// Ensure the ecommerce feature is not compulsory when no plugin is selected
			const updatedFeatures = siteFeatures.map( ( feature ) => {
				if ( feature.id === 'ecommerce' ) {
					return { ...feature, compulsory: false };
				}
				return feature;
			} );
			dispatch( {
				type: 'set',
				siteFeatures: updatedFeatures,
			} );
		}
	}, [
		selectedTemplateID,
		isEcommerce,
		selectedEcommercePlugin,
		templateRequiredPluginsList,
	] );

	const handleToggleFeature = ( featureId ) => () => {
		const updatedFeatures = siteFeatures.map( ( feature ) => {
			if ( feature.compulsory ) {
				return feature;
			}
			if ( feature.id === featureId ) {
				return { ...feature, enabled: ! feature.enabled };
			}
			return feature;
		} );

		dispatch( {
			type: 'set',
			siteFeatures: updatedFeatures,
		} );
	};

	const setNextStep = async () => {
		dispatch( {
			type: 'set',
			currentIndex: currentIndex + 1,
		} );

		const enabledFeatureIds = siteFeatures
			.filter( ( component ) => component.enabled )
			.map( ( component ) => component.id );

		dispatch( {
			type: 'set',
			enabledFeatureIds,
		} );

		storedState[ 0 ].enabledFeatureIds = enabledFeatureIds;
		storedState[ 0 ].selectedEcommercePlugin = selectedEcom;

		await checkRequiredPlugins( storedState );
	};
	const skipStep = () => {
		dispatch( {
			type: 'set',
			currentIndex: currentIndex + 1,
		} );
	};

	// Generate the list of plugins required for the selected features along with the template required plugins.
	const featurePluginsList = useMemo( () => {
		const enabledFeatureIds =
			siteFeatures
				?.filter( ( feature ) => feature.enabled )
				.map( ( feature ) => feature.id ) ?? [];

		return [
			...templateRequiredPluginsList,
			...( getFeaturePluginList(
				enabledFeatureIds,
				selectedEcom,
				templateRequiredPluginsList?.map( ( plugin ) => plugin.slug )
			) ?? [] ),
		];
	}, [ templateRequiredPluginsList, siteFeatures, selectedEcom ] );

	return (
		<>
			<Container className="grid grid-cols-1 gap-6 auto-rows-auto !max-w-[55rem] w-full mx-auto">
				<div className="space-y-4 text-left">
					<div className="space-y-3">
						<div className="text-heading-text !text-[1.75rem] font-semibold leading-9">
							{ __( 'Select features', 'astra-sites' ) }
						</div>
						<p className="text-body-text !text-base font-normal leading-6">
							{ __(
								'Select the features you want on this website',
								'astra-sites'
							) }
						</p>
					</div>
				</div>
				{ /* Feature Cards */ }
				<div className="grid grid-cols-1 lg:grid-cols-2 auto-rows-auto gap-4 w-full">
					{ siteFeatures.map( ( feature ) => {
						const isEcommerceFeature = feature.id === 'ecommerce';
						const FeatureIcon =
							ICON_SET?.[ feature?.icon ] || WrenchIcon;
						return (
							<div
								key={ feature?.id }
								className={ classNames(
									'relative py-4 pl-4 pr-5 rounded-md shadow-sm border border-solid bg-white border-button-disabled transition-colors duration-150 ease-in-out',
									feature?.enabled && 'border-classic-button',
									'cursor-pointer'
								) }
							>
								<div className="!flex !items-start !w-full">
									<FeatureIcon className="w-8 h-8 text-app-active-icon" />

									<div className="!ml-3 !w-full text-left">
										<p className="!text-md !mb-1 !text-base !font-semibold !leading-6">
											{ feature?.title }
										</p>
										<div className="flex justify-between !items-start !w-full">
											<p className="text-app-body-text text-sm font-normal leading-5 w-full">
												{ feature?.description }
											</p>
											{ isEcommerceFeature && (
												<EcommerceOptions
													ecomSupported={
														ecomSupported
													}
													selectedEcom={
														selectedEcom
													}
													onChange={ setSelectedEcom }
													dispatch={ dispatch }
												/>
											) }
										</div>
									</div>
								</div>
								{ /* Check mark */ }

								<span
									className={ classNames(
										'inline-flex absolute top-4 right-4 p-[0.1875rem] border border-solid border-zip-app-inactive-icon rounded',
										feature?.enabled &&
											'border-classic-button bg-classic-button',
										feature?.compulsory &&
											'border-button-disabled bg-button-disabled'
									) }
								>
									<CheckIcon
										className="w-2.5 h-2.5 text-white"
										strokeWidth={ 4 }
									/>
								</span>
								{ ! feature?.compulsory && (
									<div
										className="absolute inset-0 cursor-pointer"
										onClick={ handleToggleFeature(
											feature?.id
										) }
									/>
								) }
							</div>
						);
					} ) }
				</div>

				{ !! featurePluginsList?.length && (
					<RequiredPlugins pluginsList={ featurePluginsList } />
				) }

				<div className="flex justify-between items-center">
					<div className="flex gap-4 max-md:flex-col flex-1">
						<Button
							variant="primary"
							className="!bg-classic-button border border-solid border-classic-button flex gap-2 items-center h-11 text-[15px] leading-[15px]"
							onClick={ setNextStep }
						>
							<span>{ __( 'Continue', 'astra-sites' ) }</span>
							<ArrowLongRightIcon className="w-4 h-4 !fill-none" />
						</Button>

						<div className="flex justify-between items-center w-full">
							<Button
								variant="blank"
								className="!bg-transparent !text-classic-button border border-solid border-classic-button px-4 py-2 rounded inline-flex items-center justify-center h-11 text-[15px] leading-[15px]"
								onClick={ () =>
									dispatch( {
										type: 'set',
										currentIndex: currentIndex - 1,
									} )
								}
							>
								{ __( 'Back', 'astra-sites' ) }
							</Button>
							<a
								className="text-zip-body-text no-underline text-base font-normal cursor-pointer"
								onClick={ skipStep }
							>
								{ __( 'Skip this step', 'astra-sites' ) }
							</a>
						</div>
					</div>
				</div>
			</Container>
		</>
	);
};
export default ClassicFeatures;