Skip to content

Commit

Permalink
refactor(checkout): CHECKOUT-4338 Use media query component to condit…
Browse files Browse the repository at this point in the history
…ionally render checkout step
  • Loading branch information
davidchin committed Aug 20, 2019
1 parent 35a0560 commit d352673
Show file tree
Hide file tree
Showing 2 changed files with 61 additions and 40 deletions.
11 changes: 10 additions & 1 deletion src/app/checkout/CheckoutStep.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { mount } from 'enzyme';
import { noop } from 'lodash';
import React from 'react';
import { CSSTransition } from 'react-transition-group';

import { MOBILE_MAX_WIDTH } from '../ui/responsive';

import CheckoutStep, { CheckoutStepProps } from './CheckoutStep';
import CheckoutStepHeader from './CheckoutStepHeader';
import CheckoutStepType from './CheckoutStepType';
Expand All @@ -25,7 +28,13 @@ describe('CheckoutStep', () => {
window.scrollTo = jest.fn();

// Mock `matchMedia` to detect mobile viewport
window.matchMedia = jest.fn(query => ({ matches: query === '(max-width: 968px)' ? isMobile : false }) as MediaQueryList);
window.matchMedia = jest.fn(query => ({
matches: query === `(max-width: ${MOBILE_MAX_WIDTH}px)` ? isMobile : false,
addListener: noop,
addEventListener: noop,
removeListener: noop,
removeEventListener: noop,
}) as MediaQueryList);
});

afterEach(() => {
Expand Down
90 changes: 51 additions & 39 deletions src/app/checkout/CheckoutStep.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import classNames from 'classnames';
import { noop } from 'lodash';
import React, { createRef, Component, ReactNode, RefObject } from 'react';
import React, { createRef, Component, ReactNode } from 'react';
import { CSSTransition } from 'react-transition-group';

import { isMobileView, MobileView } from '../ui/responsive';

import CheckoutStepHeader from './CheckoutStepHeader';
import CheckoutStepType from './CheckoutStepType';

Expand All @@ -17,13 +19,11 @@ export interface CheckoutStepProps {
onEdit?(step: CheckoutStepType): void;
}

const LARGE_SCREEN_BREAKPOINT = 968;
const LARGE_SCREEN_ANIMATION_DELAY = 610;

export default class CheckoutStep extends Component<CheckoutStepProps> {
private containerRef = createRef<HTMLElement>();
private mobileQuery = window.matchMedia(`(max-width: ${LARGE_SCREEN_BREAKPOINT}px)`);
private containerRef = createRef<HTMLLIElement>();
private contentRef = createRef<HTMLDivElement>();
private timeoutRef?: number;
private timeoutDelay?: number;

componentDidMount(): void {
const { isActive } = this.props;
Expand Down Expand Up @@ -67,7 +67,7 @@ export default class CheckoutStep extends Component<CheckoutStepProps> {
'optimizedCheckout-checkoutStep',
{ [`checkout-step--${type}`]: !!type }
) }
ref={ this.containerRef as RefObject<HTMLLIElement> }
ref={ this.containerRef }
>
<div className="checkout-view-header">
<CheckoutStepHeader
Expand All @@ -89,42 +89,43 @@ export default class CheckoutStep extends Component<CheckoutStepProps> {
private renderContent(): ReactNode {
const { children, isActive } = this.props;

if (this.mobileQuery.matches) {
if (!isActive) {
return null;
}

return (
<div className="checkout-view-content">
{ children }
</div>
);
}

return (
<CSSTransition
addEndListener={ (node, done) => {
node.addEventListener('transitionend', ({ target }) => {
if (target === node) {
done();
}
});
return <>
<MobileView>
{ matched => {
if (matched) {
return !isActive ? null : <div className="checkout-view-content">
{ children }
</div>;
}

return <CSSTransition
addEndListener={ (node, done) => {
node.addEventListener('transitionend', ({ target }) => {
if (target === node) {
done();
}
});
} }
classNames="checkout-view-content"
timeout={ {} }
in={ isActive }
unmountOnExit
mountOnEnter
>
<div
className="checkout-view-content"
ref={ this.contentRef }
>
{ children }
</div>
</CSSTransition>;
} }
classNames="checkout-view-content"
timeout={ {} }
in={ isActive }
unmountOnExit
mountOnEnter
>
<div className="checkout-view-content">
{ children }
</div>
</CSSTransition>
);
</MobileView>
</>;
}

private focusStep(): void {
const delay = this.mobileQuery.matches ? 0 : LARGE_SCREEN_ANIMATION_DELAY;
const delay = isMobileView() ? 0 : this.getTransitionDelay();

this.timeoutRef = window.setTimeout(() => {
const input = this.getChildInput();
Expand Down Expand Up @@ -187,4 +188,15 @@ export default class CheckoutStep extends Component<CheckoutStepProps> {

return this.containerRef.current ? this.containerRef.current : undefined;
}

private getTransitionDelay(): number {
if (this.timeoutDelay !== undefined) {
return this.timeoutDelay;
}

// Cache the result to avoid unnecessary reflow
this.timeoutDelay = parseFloat(this.contentRef.current ? getComputedStyle(this.contentRef.current).transitionDuration : '0s') * 1000;

return this.timeoutDelay;
}
}

0 comments on commit d352673

Please sign in to comment.