Skip to content

Commit

Permalink
Merge pull request #2924 from woocommerce/PCP-4025-review-and-fix-com…
Browse files Browse the repository at this point in the history
…ponent-state-handling

Settings UI: Fix UI animations by removing the components prop
  • Loading branch information
stracker-phil authored Dec 17, 2024
2 parents c279a88 + 44e79f6 commit 33afa94
Show file tree
Hide file tree
Showing 14 changed files with 309 additions and 408 deletions.
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import { Icon } from '@wordpress/components';
import { chevronDown, chevronUp } from '@wordpress/icons';

import classNames from 'classnames';

import { useAccordionState } from '../../hooks/useAccordionState';

// Provide defaults for all layout components so the generic version just works.
Expand All @@ -24,6 +22,13 @@ const DefaultDescription = ( { children } ) => (
<div className="ppcp-r-accordion__description">{ children }</div>
);

const AccordionContent = ( { isOpen, children } ) => {
if ( ! isOpen || ! children ) {
return null;
}
return <div className="ppcp-r-accordion__content">{ children }</div>;
};

const Accordion = ( {
title,
id = '',
Expand Down Expand Up @@ -65,9 +70,7 @@ const Accordion = ( {
) }
</Header>
</button>
{ isOpen && children && (
<div className="ppcp-r-accordion__content">{ children }</div>
) }
<AccordionContent isOpen={ isOpen }>{ children }</AccordionContent>
</div>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,19 @@ import {
} from './SettingsBlockElements';

const SettingsAccordion = ( { title, description, children, ...props } ) => (
<SettingsBlock
{ ...props }
className="ppcp-r-settings-block__accordion"
components={ [
() => (
<Accordion
title={ title }
description={ description }
Header={ Header }
TitleWrapper={ TitleWrapper }
Title={ Title }
Action={ Action }
Description={ Description }
>
{ children }
</Accordion>
),
] }
/>
<SettingsBlock { ...props } className="ppcp-r-settings-block__accordion">
<Accordion
title={ title }
description={ description }
Header={ Header }
TitleWrapper={ TitleWrapper }
Title={ Title }
Action={ Action }
Description={ Description }
>
{ children }
</Accordion>
</SettingsBlock>
);

export default SettingsAccordion;
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,24 @@ import SettingsBlock from './SettingsBlock';
import { Header, Title, Action, Description } from './SettingsBlockElements';

const ButtonSettingsBlock = ( { title, description, ...props } ) => (
<SettingsBlock
{ ...props }
className="ppcp-r-settings-block__button"
components={ [
() => (
<>
<Header>
<Title>{ title }</Title>
<Description>{ description }</Description>
</Header>
<Action>
<Button
variant={ props.actionProps?.buttonType }
onClick={
props.actionProps?.callback
? () => props.actionProps.callback()
: undefined
}
>
{ props.actionProps.value }
</Button>
</Action>
</>
),
] }
/>
<SettingsBlock { ...props } className="ppcp-r-settings-block__button">
<Header>
<Title>{ title }</Title>
<Description>{ description }</Description>
</Header>
<Action>
<Button
variant={ props.actionProps?.buttonType }
onClick={
props.actionProps?.callback
? () => props.actionProps.callback()
: undefined
}
>
{ props.actionProps.value }
</Button>
</Action>
</SettingsBlock>
);

export default ButtonSettingsBlock;
Original file line number Diff line number Diff line change
Expand Up @@ -11,56 +11,42 @@ const FeatureSettingsBlock = ( { title, description, ...props } ) => {
}

return (
<>
<span className="ppcp-r-feature-item__notes">
{ notes.map( ( note, index ) => (
<span key={ index }>{ note }</span>
) ) }
</span>
</>
<span className="ppcp-r-feature-item__notes">
{ notes.map( ( note, index ) => (
<span key={ index }>{ note }</span>
) ) }
</span>
);
};

return (
<SettingsBlock
{ ...props }
className="ppcp-r-settings-block__feature"
components={ [
() => (
<>
<Header>
<Title>
{ title }
{ props.actionProps?.featureStatus && (
<TitleBadge
{ ...props.actionProps?.badge }
/>
) }
</Title>
<Description className="ppcp-r-settings-block__feature__description">
{ description }
{ printNotes() }
</Description>
</Header>
<Action>
<div className="ppcp-r-feature-item__buttons">
{ props.actionProps?.buttons.map(
( button ) => (
<Button
href={ button.url }
key={ button.text }
variant={ button.type }
>
{ button.text }
</Button>
)
) }
</div>
</Action>
</>
),
] }
/>
<SettingsBlock { ...props } className="ppcp-r-settings-block__feature">
<Header>
<Title>
{ title }
{ props.actionProps?.featureStatus && (
<TitleBadge { ...props.actionProps?.badge } />
) }
</Title>
<Description className="ppcp-r-settings-block__feature__description">
{ description }
{ printNotes() }
</Description>
</Header>
<Action>
<div className="ppcp-r-feature-item__buttons">
{ props.actionProps?.buttons.map( ( button ) => (
<Button
href={ button.url }
key={ button.text }
variant={ button.type }
>
{ button.text }
</Button>
) ) }
</div>
</Action>
</SettingsBlock>
);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,28 +42,20 @@ const InputSettingsBlock = ( {
order = DEFAULT_ELEMENT_ORDER,
...props
} ) => (
<SettingsBlock
{ ...props }
className="ppcp-r-settings-block__input"
components={ [
() => (
<>
{ order.map( ( elementKey ) => {
const RenderElement = ELEMENT_RENDERERS[ elementKey ];
return RenderElement ? (
<RenderElement
key={ elementKey }
title={ title }
description={ description }
supplementaryLabel={ supplementaryLabel }
actionProps={ props.actionProps }
/>
) : null;
} ) }
</>
),
] }
/>
<SettingsBlock { ...props } className="ppcp-r-settings-block__input">
{ order.map( ( elementKey ) => {
const RenderElement = ELEMENT_RENDERERS[ elementKey ];
return RenderElement ? (
<RenderElement
key={ elementKey }
title={ title }
description={ description }
supplementaryLabel={ supplementaryLabel }
actionProps={ props.actionProps }
/>
) : null;
} ) }
</SettingsBlock>
);

export default InputSettingsBlock;
Original file line number Diff line number Diff line change
Expand Up @@ -5,56 +5,43 @@ import PaymentMethodIcon from '../PaymentMethodIcon';
import data from '../../../utils/data';

const PaymentMethodItemBlock = ( props ) => {
const [ paymentMethodState, setPaymentMethodState ] = useState();
const [ toggleIsChecked, setToggleIsChecked ] = useState( false );
const [ modalIsVisible, setModalIsVisible ] = useState( false );
const Modal = props?.modal;

const handleCheckboxState = ( checked ) => {
setPaymentMethodState( checked ? props.id : null );
};

return (
<>
<SettingsBlock
className="ppcp-r-settings-block__payment-methods__item"
components={ [
() => (
<div className="ppcp-r-settings-block__payment-methods__item__inner">
<div className="ppcp-r-settings-block__payment-methods__item__title-wrapper">
<PaymentMethodIcon
icons={ [ props.icon ] }
type={ props.icon }
/>
<span className="ppcp-r-settings-block__payment-methods__item__title">
{ props.title }
</span>
</div>
<p className="ppcp-r-settings-block__payment-methods__item__description">
{ props.description }
</p>
<div className="ppcp-r-settings-block__payment-methods__item__footer">
<ToggleControl
__nextHasNoMarginBottom={ true }
checked={ props.id === paymentMethodState }
onChange={ handleCheckboxState }
/>
{ Modal && (
<div
className="ppcp-r-settings-block__payment-methods__item__settings"
onClick={ () =>
setModalIsVisible( true )
}
>
{ data().getImage(
'icon-settings.svg'
) }
</div>
) }
<SettingsBlock className="ppcp-r-settings-block__payment-methods__item">
<div className="ppcp-r-settings-block__payment-methods__item__inner">
<div className="ppcp-r-settings-block__payment-methods__item__title-wrapper">
<PaymentMethodIcon
icons={ [ props.icon ] }
type={ props.icon }
/>
<span className="ppcp-r-settings-block__payment-methods__item__title">
{ props.title }
</span>
</div>
<p className="ppcp-r-settings-block__payment-methods__item__description">
{ props.description }
</p>
<div className="ppcp-r-settings-block__payment-methods__item__footer">
<ToggleControl
__nextHasNoMarginBottom={ true }
checked={ toggleIsChecked }
onChange={ setToggleIsChecked }
/>
{ Modal && (
<div
className="ppcp-r-settings-block__payment-methods__item__settings"
onClick={ () => setModalIsVisible( true ) }
>
{ data().getImage( 'icon-settings.svg' ) }
</div>
</div>
),
] }
/>
) }
</div>
</div>
</SettingsBlock>
{ Modal && modalIsVisible && (
<Modal setModalIsVisible={ setModalIsVisible } />
) }
Expand Down
Original file line number Diff line number Diff line change
@@ -1,27 +1,33 @@
import { useState, useCallback } from '@wordpress/element';
import SettingsBlock from './SettingsBlock';
import PaymentMethodItemBlock from './PaymentMethodItemBlock';

const PaymentMethodsBlock = ( { paymentMethods, className = '' } ) => {
const [ selectedMethod, setSelectedMethod ] = useState( null );

const handleSelect = useCallback( ( methodId, isSelected ) => {
setSelectedMethod( isSelected ? methodId : null );
}, [] );

if ( paymentMethods.length === 0 ) {
return null;
}

return (
<SettingsBlock
className={ `ppcp-r-settings-block__payment-methods ${ className }` }
components={ [
() => (
<>
{ paymentMethods.map( ( paymentMethod ) => (
<PaymentMethodItemBlock
key={ paymentMethod.id }
{ ...paymentMethod }
/>
) ) }
</>
),
] }
/>
>
{ paymentMethods.map( ( paymentMethod ) => (
<PaymentMethodItemBlock
key={ paymentMethod.id }
{ ...paymentMethod }
isSelected={ selectedMethod === paymentMethod.id }
onSelect={ ( checked ) =>
handleSelect( paymentMethod.id, checked )
}
/>
) ) }
</SettingsBlock>
);
};

Expand Down
Loading

0 comments on commit 33afa94

Please sign in to comment.