...
Whitelabel:
...
Components tree architecture
...
Tasks breakdown
The solution was based on the Sodexo Voucher implementation: https://github.com/rbilabs/intl-whitelabel-app/pull/686/files
Task 1: Create a new feature flag
Flag should be added in: frontend/src/utils/launchdarkly/flags.ts
Suggestion name: ENABLE_CREDIT_CARD_AT_HOME_PAYCOMET
Task X: Add the new payment method in the payment state and structure
Create a new placeholder for the new payment method
Expand |
---|
title | frontend/src/state/payment/constants.ts |
---|
|
Code Block |
---|
| // Replace this name for what we decide
export const NEW_PAYMENT_METHOD_PLACEHOLDER: IPaymentMethod = {
sodexo: false,
fdAccountId: 'CASH',
accountIdentifier: 'NEW_PAYMENT_METHOD', // TO BE DEFINED
paymentMethodBrand: 'NEW_PAYMENT_METHOD', // TO BE DEFINED
chaseProfileId: null,
credit: null,
prepaid: null,
paypalIdentifier: null,
ideal: null,
paypal: false,
}; |
|
Add the new payment method in getPaymentMethodsState
:
Expand |
---|
title | frontend/src/state/payment/hooks/getPaymentMethodsState/index.ts |
---|
|
Update the interface: frontend/src/state/payment/hooks/types.ts :
Code Block |
---|
| export interface ISetupPaymentMethodState {
enableNewMethod: boolean;
} |
Adjust the getPaymentMethodsState : Code Block |
---|
| export const getPaymentMethodsState = ({
// ... rest of the code
enableNewMethod,
}: ISetupPaymentMethodState) => {
// ... rest of the code
if (enableNewMethod) {
availablePaymentMethodList.push(NEW_PAYMENT_METHOD_PLACEHOLDER);
}
// ... rest of the code
}; |
|
Expand |
---|
title | frontend/src/state/payment/hooks/use-payment.tsx |
---|
|
Update cash account variable: Code Block |
---|
| const cashAccount: IPaymentMethod = {
// ... rest of the code
newMethod: null,
}; |
Add the new feature flag here and then pass through the getPaymentMethodState : Code Block |
---|
| const usePayment = ({
// ... rest of the code
const enableNewMethod = useFlag(LaunchDarklyFlag.ENABLE_CREDIT_CARD_AT_HOME_PAYCOMET); // new line
const initPaymentMethods = useCallback(() => {
const {
availablePaymentMethodList,
validDefaultPaymentMethodId,
validDefaultReloadPaymentMethodId,
} = getPaymentMethodsState({
enableNewMethod, // new line here
});
},
[]
);
}); |
Adjust the unit tests mocking the new flag where necessary: frontend/src/state/payment/tests/use-payment.test.tsx |
Adjust use-order-payment
hook
Expand |
---|
title | frontend/src/pages/cart/payment/order-payment/use-order-payment.ts |
---|
|
Add a new state for the new payment method: const [isPaycometNewMethodSelected, setIsPaycometNewMethodSelected] = useState('');
Update the handlePaymentMethodSelected adding the new method: Code Block |
---|
| const handlePaymentMethodSelected = (newFdAccountId?: string) => {
if (!newFdAccountId) {
payment.setCheckoutPaymentMethodId('');
return;
}
// ... rest of the code
setIsPaycometNewMethodSelected(''); // New line
}; |
Clear our new method in the useEffect logic that already exist: Code Block |
---|
| // when checkout payment method have been updated from payment context
// the flags to show add new credit card or add gift card
// have to be updated.
useEffect(() => {
// ... rest of the code
setIsPaycometNewMethodSelected('');
}
}, [setCheckoutPaymentMethodId, checkoutPaymentMethodId]); |
Update the placeOrder function to deal with the new method: |
Task 2: Create and add a new method in payment-method-option structure
...
Add the new icon for the new payment method in: frontend/src/components/icons/new-payment-method/index.tsx
(replace “new-payment-method” for the new name, hahaha).
Add the new method option in the interface of payment methods:
Expand |
---|
title | frontend/src/state/payment/types.ts |
---|
|
Code Block |
---|
| export interface IPaymentMethod {
// ... rest of the code
newPaymentMethod?: boolean | null;
} |
|
Expand |
---|
title | frontend/src/components/payment-method-option/new-payment-method.tsx (example of new file) |
---|
|
Code Block |
---|
| import React from 'react';
import { useIntl } from 'react-intl';
import { MethodType } from './styled';
const NewPaymentMethod = () => { // Example SodexoMethod
const { formatMessage } = useIntl();
return <MethodType>{formatMessage({ id: 'payWithNewMethod' })}</MethodType>;
};
export default NewPaymentMethod; |
|
...
Expand |
---|
title | frontend/src/components/payment-method-option/index.tsx |
---|
|
Adjust the RenderMethodType and add the new method created above Code Block |
---|
|
const RenderMethodType = () => {
// ... rest of the code
// New if here
if (method.newPaymentMethod) {
return <NewPaymentMethod />;
}
return null;
};
// add the new payment method inside the <MethodTypeWrapper> in the return
return
// rest of the code
(
// rest of the code
<MethodTypeWrapper
data-private
data-dd-privacy="mask"
onClick={onClickMethod}
$isClickable={!!onClick}
disableMethod={disableMethod}
fromCheckout={fromCheckout}
data-testid={`method-type-wrapper-${method.accountIdentifier ?? method.fdAccountId ?? ''}`}
selected={selected}
>
// rest of the code
<div>
<MethodTypeDescription>
// Add new method here inside the description
{method.newPaymentMethod && <StyledNewPaymentMethodCardIcon />}
</MethodTypeDescription>
// rest of the code
</div>
</MethodTypeWrapper>
// rest of the code
); |
|
Task X: Adjust account payment method lists to deal with the new method
...
Expand |
---|
title | frontend/src/components/payment-method-flat-list-with-button/payment-method-flat-list-with-button.tsx |
---|
|
We’ll exclude the new payment method if it is not actually stored in the user account: Code Block |
---|
| function filterOutUnsupportedPaymentMethods(paymentMethods: IPaymentMethod[]) {
return paymentMethods.filter(
n =>
n.accountIdentifier !== PAYPAL_PAYMENT_METHOD_PLACEHOLDER.accountIdentifier &&
n.accountIdentifier !== SODEXO_VOUCHER_PAYMENT_METHOD_PLACEHOLDER.accountIdentifier &&
n.accountIdentifier !== NEW_PAYMENT_METHOD_PLACEHOLDER.accountIdentifier &&
);
} |
|