Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(payment): STRIPE-444 New Stripe UPE (PoC) #2018

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import React, { FunctionComponent, memo, useCallback, useMemo } from 'react';

import { connectFormik, ConnectFormikProps } from '../../common/form';
import { isMobile } from '../../common/utility';
import { Checklist, ChecklistItem } from '../../ui/form';
import { Checklist, ChecklistItem, CustomChecklistItem } from '../../ui/form';

import getUniquePaymentMethodId, { parseUniquePaymentMethodId } from './getUniquePaymentMethodId';
import PaymentMethodTitle from './PaymentMethodTitle';
Expand Down Expand Up @@ -116,6 +116,15 @@ const PaymentMethodListItem: FunctionComponent<PaymentMethodListItemProps> = ({
[method],
);

if (method.initializationData?.accordion) { // TODO: accordion key will be changed to more relevant after changes on BCapp side
return (
<CustomChecklistItem
content={renderPaymentMethod}
htmlId={`radio-${value}`}
/>
);
}

return (
<ChecklistItem
content={renderPaymentMethod}
Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/app/ui/form/Checklist.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,9 @@ import React, {
useMemo,
} from 'react';

import { Accordion } from '@bigcommerce/checkout/ui';

import { connectFormik, ConnectFormikProps } from '../../common/form';
import { Accordion } from '../accordion';

export interface ChecklistProps {
children: ReactNode;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/app/ui/form/ChecklistItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { FieldProps } from 'formik';
import { kebabCase } from 'lodash';
import React, { FunctionComponent, memo, ReactNode, useCallback, useContext } from 'react';

import { AccordionItem, AccordionItemHeaderProps } from '../accordion';
import { AccordionItem, AccordionItemHeaderProps } from '@bigcommerce/checkout/ui';

import BasicFormField from './BasicFormField';
import { ChecklistContext } from './Checklist';
Expand Down
22 changes: 22 additions & 0 deletions packages/core/src/app/ui/form/CustomChecklistItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import React, { FunctionComponent, memo, ReactNode } from 'react';

export interface CustomChecklistItemProps {
content?: ReactNode;
htmlId?: string;
}

const CustomChecklistItem: FunctionComponent<CustomChecklistItemProps> = ({
content,
htmlId,
}) => {
return (
<li
className="form-checklist-item optimizedCheckout-form-checklist-item custom-checklist-item"
id={htmlId}
>
{content}
</li>
);
};

export default memo(CustomChecklistItem);
1 change: 1 addition & 0 deletions packages/core/src/app/ui/form/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,6 @@ export { default as CheckboxInput } from './CheckboxInput';
export { default as Label, LabelProps } from './Label';
export { default as Legend, LegendProps } from './Legend';
export { default as ChecklistItemInput, ChecklistItemInputProps } from './ChecklistItemInput';
export { default as CustomChecklistItem, CustomChecklistItemProps } from './CustomChecklistItem';
export { default as DynamicFormField } from './DynamicFormField';
export { default as DynamicFormFieldType } from './DynamicFormFieldType';
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,14 @@
will-change: $loading-skeleton-will-change;
}
}

.custom-checklist-item {
margin: 0;
overflow: hidden;
border-bottom: 0;

.paymentMethod--hosted,
.widget {
padding: 0;
}
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
import { PaymentInitializeOptions } from '@bigcommerce/checkout-sdk';
import { noop, some } from 'lodash';
import React, { FunctionComponent, useCallback, useMemo } from 'react';
import React, {
FunctionComponent,
useCallback,
useContext,
useEffect,
useMemo,
useRef,
} from 'react';

import { getAppliedStyles } from '@bigcommerce/checkout/dom-utils';
import { HostedWidgetPaymentComponent } from '@bigcommerce/checkout/hosted-widget-integration';
Expand All @@ -13,6 +20,7 @@ import {
PaymentMethodResolveId,
toResolvableComponent,
} from '@bigcommerce/checkout/payment-integration-api';
import { AccordionContext } from '@bigcommerce/checkout/ui';

const StripeUPEPaymentMethod: FunctionComponent<PaymentMethodProps> = ({
paymentForm,
Expand All @@ -22,9 +30,19 @@ const StripeUPEPaymentMethod: FunctionComponent<PaymentMethodProps> = ({
onUnhandledError = noop,
...rest
}) => {
const collapseStripeElement = useRef<() => void>();
const { onToggle, selectedItemId } = useContext(AccordionContext);
const containerId = `stripe-${method.id}-component-field`;
const paymentContext = paymentForm;

useEffect(() => {
if (selectedItemId?.includes('stripeupe-')) {
return;
}

collapseStripeElement.current?.();
}, [selectedItemId]);

const renderSubmitButton = useCallback(() => {
paymentContext.hidePaymentSubmitButton(method, false);
}, [paymentContext, method]);
Expand Down Expand Up @@ -69,6 +87,10 @@ const StripeUPEPaymentMethod: FunctionComponent<PaymentMethodProps> = ({
return getAppliedStyles(parentContainer, properties);
};

// const accordionCollapseListener = (collapseElement: () => void) => {
// collapseStripeElement.current = collapseElement;
// };

const initializeStripePayment = useCallback(
async (options: PaymentInitializeOptions) => {
const formInput = getStylesFromElement(`${containerId}--input`, [
Expand Down Expand Up @@ -97,6 +119,10 @@ const StripeUPEPaymentMethod: FunctionComponent<PaymentMethodProps> = ({
},
onError: onUnhandledError,
render: renderSubmitButton,
paymentMethodSelect: onToggle,
handleClosePaymentMethod: (collapseElement: () => void) => {
collapseStripeElement.current = collapseElement;
},
},
});
},
Expand All @@ -107,6 +133,7 @@ const StripeUPEPaymentMethod: FunctionComponent<PaymentMethodProps> = ({
method,
paymentContext,
renderSubmitButton,
onToggle,
],
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface AccordionState {
export default class Accordion extends Component<AccordionProps, AccordionState> {
state: AccordionState = {};

private getContextValue = memoizeOne((selectedItemId) => {
private getContextValue = memoizeOne((selectedItemId?: string) => {
return {
onToggle: this.handleToggleItem,
selectedItemId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ const AccordionItem: FunctionComponent<AccordionItemProps> = ({
const { onToggle, selectedItemId } = useContext(AccordionContext);
const isSelected = selectedItemId === itemId;

const transitionEndListener = useCallback((node, done) => {
const transitionEndListener = useCallback((node: Node, done) => {
node.addEventListener('transitionend', ({ target }: Event) => {
if (target === node) {
done();
Expand All @@ -42,14 +42,12 @@ const AccordionItem: FunctionComponent<AccordionItemProps> = ({
}, []);

return (
<li
className={classNames(className, { [classNameSelected]: isSelected })}
>
<li className={classNames(className, { [classNameSelected]: isSelected })}>
<div className={classNames(headerClassName, { [headerClassNameSelected]: isSelected })}>
{headerContent({ isSelected, onToggle })}
</div>

{children && (
{children ? (
<CSSTransition
addEndListener={transitionEndListener}
classNames={bodyClassName}
Expand All @@ -60,7 +58,7 @@ const AccordionItem: FunctionComponent<AccordionItemProps> = ({
>
<div className={bodyClassName}>{children}</div>
</CSSTransition>
)}
) : undefined}
</li>
);
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ export {
AccordionItemHeaderProps,
AccordionItemProps,
} from './AccordionItem';
export { default as AccordionContext, AccordionContextProps } from './AccordionContext';
9 changes: 9 additions & 0 deletions packages/ui/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
/* istanbul ignore file */
export { Alert, AlertType } from './alert';
export {
Accordion,
AccordionProps,
AccordionItem,
AccordionItemHeaderProps,
AccordionItemProps,
AccordionContext,
AccordionContextProps,
} from './accordion';
export { Button, ButtonSize, ButtonVariant } from './button';
export { DropdownTrigger } from './dropdown';
export {
Expand Down