Skip to content

Commit

Permalink
Add iDEAL payment method to UPE (#2681)
Browse files Browse the repository at this point in the history
* Add payment method class for iDEAL
  • Loading branch information
daquinons authored Aug 9, 2021
1 parent ef3c7fd commit b972a9d
Show file tree
Hide file tree
Showing 25 changed files with 409 additions and 22 deletions.
5 changes: 5 additions & 0 deletions assets/css/admin.css
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,11 @@
background-size: contain;
}

.payment-method__brand--ideal {
background: no-repeat url( '../images/payment-methods/ideal.svg' );
background-size: contain;
}

.payment-method__brand--google-pay {
background: no-repeat url( '../images/cards/google-pay.svg' );
background-size: contain;
Expand Down
38 changes: 38 additions & 0 deletions assets/images/payment-methods/ideal.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
*** WooCommerce Payments Changelog ***

= 2.9.0 - 2021-xx-xx =
* Add - *Early access*: allow your store to collect payments with iDEAL. Enable the feature in settings!

= 2.8.2 - 2021-08-05 =
* Fix - If account is disconnected or not set up do not display onboarding task and UPE inbox note.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,13 @@ const AddPaymentMethodsTask = () => {
name="sepa_debit"
/>
) }
{ availablePaymentMethods.includes( 'ideal' ) && (
<PaymentMethodCheckbox
checked={ paymentMethodsState.ideal }
onChange={ handlePaymentMethodChange }
name="ideal"
/>
) }
</PaymentMethodCheckboxes>
</CardBody>
</Card>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,9 @@ const usePaymentMethodsCheckboxState = () => {
// by default, all the checkboxes should be "checked"
availablePaymentMethods
.filter( ( method ) =>
[ 'giropay', 'sofort', 'sepa_debit' ].includes( method )
[ 'giropay', 'sofort', 'sepa_debit', 'ideal' ].includes(
method
)
)
.reduce(
( map, paymentMethod ) => ( {
Expand Down Expand Up @@ -234,6 +236,19 @@ const AddPaymentMethodsTask = () => {
name="sepa_debit"
/>
) }
{ availablePaymentMethods.includes(
'ideal'
) && (
<PaymentMethodCheckbox
checked={
paymentMethodsState.ideal
}
onChange={
handlePaymentMethodChange
}
name="ideal"
/>
) }
</PaymentMethodCheckboxes>
</LoadableSettingsSection>
</LoadableBlock>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ describe( 'AddPaymentMethodsTask', () => {
'card',
'giropay',
'sepa_debit',
'ideal',
] );
useSettings.mockReturnValue( {
saveSettings: () => Promise.resolve( true ),
Expand Down Expand Up @@ -108,6 +109,9 @@ describe( 'AddPaymentMethodsTask', () => {
expect(
screen.getByRole( 'checkbox', { name: 'giropay' } )
).toBeChecked();
expect(
screen.getByRole( 'checkbox', { name: 'iDEAL' } )
).toBeChecked();
expect(
screen.getByRole( 'checkbox', { name: 'Direct debit payment' } )
).toBeChecked();
Expand All @@ -120,6 +124,7 @@ describe( 'AddPaymentMethodsTask', () => {
userEvent.click(
screen.getByRole( 'checkbox', { name: 'Direct debit payment' } )
);
userEvent.click( screen.getByRole( 'checkbox', { name: 'iDEAL' } ) );

// no "euro" text when no elements are checked
expect(
Expand Down Expand Up @@ -157,6 +162,9 @@ describe( 'AddPaymentMethodsTask', () => {
expect(
screen.getByRole( 'checkbox', { name: 'Direct debit payment' } )
).toBeChecked();
expect(
screen.getByRole( 'checkbox', { name: 'iDEAL' } )
).toBeChecked();
expect(
screen.queryByRole( 'checkbox', { name: /Credit/ } )
).not.toBeInTheDocument();
Expand All @@ -167,6 +175,7 @@ describe( 'AddPaymentMethodsTask', () => {
'card',
'giropay',
'sepa_debit',
'ideal',
] );
await waitFor( () =>
expect( setCompletedMock ).toHaveBeenCalledWith(
Expand All @@ -180,7 +189,7 @@ describe( 'AddPaymentMethodsTask', () => {
const setCompletedMock = jest.fn();
const updateEnabledPaymentMethodsMock = jest.fn();
useEnabledPaymentMethodIds.mockReturnValue( [
[ 'card', 'giropay' ],
[ 'card', 'giropay', 'ideal' ],
updateEnabledPaymentMethodsMock,
] );
render(
Expand All @@ -200,19 +209,24 @@ describe( 'AddPaymentMethodsTask', () => {
expect(
screen.getByRole( 'checkbox', { name: 'Direct debit payment' } )
).toBeChecked();
expect(
screen.getByRole( 'checkbox', { name: 'iDEAL' } )
).toBeChecked();

// un-check giropay
userEvent.click( screen.getByRole( 'checkbox', { name: 'giropay' } ) );
// un-check iDEAL
userEvent.click( screen.getByRole( 'checkbox', { name: 'iDEAL' } ) );
userEvent.click( screen.getByText( 'Add payment methods' ) );

// giropay is removed
// giropay and iDEAL are removed
expect( updateEnabledPaymentMethodsMock ).toHaveBeenCalledWith( [
'card',
'sepa_debit',
] );
await waitFor( () =>
expect( setCompletedMock ).toHaveBeenCalledWith(
{ initialMethods: [ 'card', 'giropay' ] },
{ initialMethods: [ 'card', 'giropay', 'ideal' ] },
'setup-complete'
)
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ describe( 'SetupComplete', () => {
};

useEnabledPaymentMethodIds.mockReturnValue( [
[ 'card', 'giropay', 'sofort' ],
[ 'card', 'giropay', 'sofort', 'ideal' ],
() => null,
] );
} );
Expand Down Expand Up @@ -99,7 +99,12 @@ describe( 'SetupComplete', () => {
value={ {
completedTasks: {
'add-payment-methods': {
initialMethods: [ 'card', 'giropay', 'sofort' ],
initialMethods: [
'card',
'giropay',
'sofort',
'ideal',
],
},
},
} }
Expand All @@ -125,7 +130,12 @@ describe( 'SetupComplete', () => {
value={ {
completedTasks: {
'add-payment-methods': {
initialMethods: [ 'card', 'giropay', 'sofort' ],
initialMethods: [
'card',
'giropay',
'sofort',
'ideal',
],
},
},
} }
Expand Down Expand Up @@ -169,7 +179,7 @@ describe( 'SetupComplete', () => {

it( 'renders setup complete messaging when context value says that more than one payment method has been added', () => {
useEnabledPaymentMethodIds.mockReturnValue( [
[ 'card', 'giropay', 'sofort', 'sepa_debit' ],
[ 'card', 'giropay', 'sofort', 'sepa_debit', 'ideal' ],
() => null,
] );
render(
Expand All @@ -189,7 +199,7 @@ describe( 'SetupComplete', () => {
);

expect( screen.getByText( /Setup complete/ ) ).toHaveTextContent(
'Setup complete! 3 new payment methods are now live on your store!'
'Setup complete! 4 new payment methods are now live on your store!'
);
} );
} );
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const CurrencyInformationForMethods = ( { selectedMethods } ) => {
}

const enabledMethodsRequiringEuros = selectedMethods.filter( ( method ) =>
[ 'giropay', 'sepa_debit', 'sofort' ].includes( method )
[ 'giropay', 'sepa_debit', 'sofort', 'ideal' ].includes( method )
);

if ( 0 === enabledMethodsRequiringEuros.length ) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ describe( 'CurrencyInformationForMethods', () => {
const { container } = render(
<FlagsContextWrapper multiCurrency={ false }>
<CurrencyInformationForMethods
selectedMethods={ [ 'card', 'giropay' ] }
selectedMethods={ [ 'card', 'giropay', 'ideal' ] }
/>
</FlagsContextWrapper>
);
Expand All @@ -61,7 +61,7 @@ describe( 'CurrencyInformationForMethods', () => {
const { container } = render(
<FlagsContextWrapper>
<CurrencyInformationForMethods
selectedMethods={ [ 'card', 'giropay' ] }
selectedMethods={ [ 'card', 'giropay', 'ideal' ] }
/>
</FlagsContextWrapper>
);
Expand All @@ -84,7 +84,7 @@ describe( 'CurrencyInformationForMethods', () => {
const { container } = render(
<FlagsContextWrapper>
<CurrencyInformationForMethods
selectedMethods={ [ 'giropay', 'card' ] }
selectedMethods={ [ 'giropay', 'card', 'ideal' ] }
/>
</FlagsContextWrapper>
);
Expand Down Expand Up @@ -118,7 +118,7 @@ describe( 'CurrencyInformationForMethods', () => {
render(
<FlagsContextWrapper>
<CurrencyInformationForMethods
selectedMethods={ [ 'card', 'giropay' ] }
selectedMethods={ [ 'card', 'giropay', 'ideal' ] }
/>
</FlagsContextWrapper>
);
Expand Down
1 change: 1 addition & 0 deletions client/components/payment-method-details/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const formatDetails = ( payment ) => {
case 'giropay':
return <Fragment>{ paymentMethod.bank_code }</Fragment>;
case 'sofort':
case 'ideal':
return (
<Fragment>
&nbsp;&bull;&bull;&bull;&bull;&nbsp;
Expand Down
11 changes: 10 additions & 1 deletion client/components/payment-methods-checkboxes/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,27 +33,36 @@ describe( 'PaymentMethodsCheckboxes', () => {
checked={ false }
name="giropay"
/>
<PaymentMethodsCheckbox
onChange={ handleChange }
checked={ false }
name="ideal"
/>
</PaymentMethodsCheckboxes>
);

const paymentMethods = screen.getAllByRole( 'listitem' );
const sepa = within( paymentMethods[ 0 ] );
const sofort = within( paymentMethods[ 1 ] );
const giropay = within( paymentMethods[ 2 ] );
const ideal = within( paymentMethods[ 3 ] );

expect( sepa.getByRole( 'checkbox' ) ).toBeChecked();
expect( sofort.getByRole( 'checkbox' ) ).not.toBeChecked();
expect( giropay.getByRole( 'checkbox' ) ).not.toBeChecked();
expect( ideal.getByRole( 'checkbox' ) ).not.toBeChecked();

userEvent.click( sepa.getByRole( 'checkbox' ) );
userEvent.click( giropay.getByRole( 'checkbox' ) );
userEvent.click( ideal.getByRole( 'checkbox' ) );

expect( handleChange ).toHaveBeenCalledTimes( 2 );
expect( handleChange ).toHaveBeenCalledTimes( 3 );
expect( handleChange ).toHaveBeenNthCalledWith(
1,
'sepa_debit',
false
);
expect( handleChange ).toHaveBeenNthCalledWith( 2, 'giropay', true );
expect( handleChange ).toHaveBeenNthCalledWith( 3, 'ideal', true );
} );
} );
36 changes: 36 additions & 0 deletions client/gateway-icons/ideal.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/* eslint-disable max-len */
/**
* External dependencies
*/
import React from 'react';

export default ( props ) => (
<svg
id="prefix__Layer_1"
xmlns="http://www.w3.org/2000/svg"
x={ 0 }
y={ 0 }
viewBox="0 0 306.1 269.8"
xmlSpace="preserve"
{ ...props }
>
<style>{ '.prefix__st0{fill:#fff}' }</style>
<path
className="prefix__st0"
d="M0 20v229.8c0 11 9 20 20 20h137.3c103.8 0 148.8-58.1 148.8-135.2C306.1 57.9 261.1 0 157.3 0H20C9 0 0 9 0 20z"
/>
<path
d="M91.9 56.4v169.8h73.9c67.1 0 96.2-37.9 96.2-91.5 0-51.3-29.1-91.1-96.2-91.1h-61.1c-7.1 0-12.8 5.8-12.8 12.8z"
fill="#c06"
/>
<path d="M157.3 251.5H37.9c-10.6 0-19.2-8.6-19.2-19.2V37.6c0-10.6 8.6-19.2 19.2-19.2h119.4c113.3 0 130.2 72.9 130.2 116.3 0 75.3-46.3 116.8-130.2 116.8zM37.9 24.8c-7.1 0-12.8 5.7-12.8 12.8v194.7c0 7.1 5.7 12.8 12.8 12.8h119.4c79.8 0 123.8-39.2 123.8-110.4 0-95.6-77.6-109.9-123.8-109.9H37.9z" />
<path
className="prefix__st0"
d="M117.9 111.8c2.6 0 5 .4 7.3 1.2 2.3.8 4.2 2.1 5.9 3.7 1.6 1.7 2.9 3.8 3.9 6.2.9 2.5 1.4 5.4 1.4 8.8 0 3-.4 5.7-1.1 8.2-.8 2.5-1.9 4.7-3.4 6.5-1.5 1.8-3.4 3.2-5.7 4.3-2.3 1-5 1.6-8.1 1.6h-17.5v-40.6h17.3zm-.6 33.1c1.3 0 2.5-.2 3.8-.6 1.2-.4 2.3-1.1 3.2-2.1.9-1 1.7-2.2 2.3-3.8.6-1.6.9-3.4.9-5.7 0-2-.2-3.9-.6-5.5-.4-1.6-1.1-3.1-2-4.2s-2.1-2.1-3.6-2.7c-1.5-.6-3.3-.9-5.5-.9h-6.4V145h7.9zM172.5 111.8v7.5h-21.4v8.7h19.7v6.9h-19.7v9.9H173v7.5h-30.8v-40.6h30.3zM203.1 111.8l15.2 40.6H209l-3.1-9h-15.2l-3.2 9h-9l15.3-40.6h9.3zm.5 24.9l-5.1-14.9h-.1l-5.3 14.9h10.5zM232.8 111.8v33.1h19.8v7.5h-28.7v-40.6h8.9z"
/>
<g>
<circle cx={ 58.5 } cy={ 132.1 } r={ 18.7 } />
</g>
<path d="M72.6 226.2c-15.7 0-28.3-12.7-28.3-28.3v-22.1c0-7.8 6.3-14.2 14.2-14.2 7.8 0 14.2 6.3 14.2 14.2v50.4z" />
</svg>
);
Loading

0 comments on commit b972a9d

Please sign in to comment.