UNPKG

@rocketsofawesome/mirage

Version:

[Live Demo of the Pattern Library](https://rocketsofawesome.github.io/mirage/)

349 lines (318 loc) 9.43 kB
import React from 'react' import PropTypes from 'prop-types' import { Elements } from 'react-stripe-elements' import styled from 'styled-components' import accounting from 'accounting' import { H3, H4, ButtonLink, ProgressBar, FreeShippingText, PersistentCartProductList, XIcon, PaymentRequestForm, CouponCodeWrapper, P } from 'SRC' const Overlay = styled.div` height: 100%; width: 100%; background-color: rgba(204, 204, 204, 0.5); ` const CartSidebarContainer = styled.article` background-color: ${props => props.theme.colors.white}; right: 0px; display: flex; flex-direction: column; padding: 20px 10px; position: fixed; left: 0; right: 0px; top: 0; bottom: 0; overflow-y: auto; ${props => props.theme.breakpointsVerbose.aboveTablet` left: auto; width: 45%; border-left: 1px solid ${props => props.theme.colors.rocketBlue}; `} ${props => props.theme.breakpointsVerbose.aboveTabletMax` width: 35%; `} ${props => props.theme.breakpointsVerbose.aboveLaptop` width: 25%; `} ` const CartSidebarHeader = styled.div` align-content: center; align-items: center; justify-content: space-between; ` const ItemCount = styled.h5` text-align: center; justify-content: center; color: ${props => props.theme.colors.navy}; letter-spacing: 1px; font-weight: 200; font-size: 18px; font-family: ${props => props.theme.fonts.primaryFont}; margin: 0 5px; display: inline-block; ` const TitleContainer = styled.div` text-align: center; ` const YourBagTitle = styled(H3)` text-align: center; margin-top: 0; display: inline-block; ` const RiskReducerContainer = styled.div` text-transform: uppercase; text-align: center; ` const CloseXDiv = styled.div` position: absolute; top: 30px; right: 30px; ` const FreeShippingDiv = styled.div` text-align: center; ` const Footer = styled.footer` background-color: ${props => props.theme.colors.white}; margin-top: auto; padding: 20px 10px; text-align: center; position: fixed; bottom: 0; left: 0; right: 0; max-height: 365px; border-top: 1px solid ${props => props.theme.colors.gray4}; ${props => props.theme.breakpointsVerbose.aboveTablet` left: auto; width: 45%; border-left: 1px solid ${props => props.theme.colors.rocketBlue}; `} ${props => props.theme.breakpointsVerbose.aboveTabletMax` left: auto; width: 35%; `} ${props => props.theme.breakpointsVerbose.aboveLaptop` width: 25%; `} } ` const Total = styled(H4)` color: ${props => props.theme.colors.navy}; letter-spacing: 0.5px; font-size: 20px; font-family: ${props => props.theme.fonts.headerFont}; margin-top: 0; ` const Em = styled.em` margin-left: 12px; font-style: normal; ` const PaymentRequestButton = styled(PaymentRequestForm)` width: 100%; max-width: 30rem; margin: 0 auto; margin-bottom: 20px; ` const CheckoutLink = styled(({ renderLink, children, ...props }) => { delete props.light delete props.uppercase delete props.underline delete props.fontFamily delete props.fontSize delete props.fontWeight if (renderLink) { return renderLink({...props, children: children}) } else { return (<a {...props}>{children}</a>) } })` line-height: 40px; display: block; vertical-align: middle; cursor: pointer; color: ${props => props.theme.colors.rocketBlue}; font-size: 14px; letter-spacing: 0.5; font-family: ${props => props.theme.fonts.primaryFont}; ` class BaseCartSidebar extends React.Component { constructor (props) { super(props) this.bag = undefined } componentDidMount () { if (this.props.shouldShowCartSidebar) { document.body.style.overflow = 'hidden' } } componentDidUpdate (prevProps, prevState) { const { shouldShowCartSidebar } = this.props if (prevProps.shouldShowCartSidebar === true && shouldShowCartSidebar === false) { document.body.style.overflow = 'inherit' } else if (prevProps.shouldShowCartSidebar === false && shouldShowCartSidebar === true) { document.body.style.overflow = 'hidden' } } componentWillUnmount () { document.body.style.overflow = 'inherit' } setBag = (element) => { this.bag = element } submitCheckout = async ({ token, ...data }) => { return this.props.submitBagCheckoutStripe(this.props.order.id, { token, ...data }) } render () { const { shouldShowCartSidebar, className, hideCartSidebar, subTotal, itemsInBag, order, setShippingAddress, renderLink, updateBag, removeItem, segmentCartViewed, lineItems, promotion, promotionLoading, promoHasBeenApplied, promoErrorMessage, applyPromotion, removePromotion, appliedPromotion, renderProductLink, pricingTestOn, currentUserEmail, onClickCheckout, onClickPaymentRequestButton } = this.props if (!shouldShowCartSidebar) return null const isCheckoutButtonDisabled = subTotal === 0 const percentage = 100 - Math.min(parseFloat(subTotal) / 50 * 100, 100) return ( <div className={className}> <Overlay onClick={hideCartSidebar} /> <CartSidebarContainer aria-label='Bag' ref={this.setBag} tabIndex='-1'> <div> <CartSidebarHeader> <TitleContainer> <YourBagTitle>Your bag</YourBagTitle> <ItemCount>({itemsInBag} {itemsInBag !== 1 ? 'items' : 'item'})</ItemCount> </TitleContainer> <CloseXDiv onClick={hideCartSidebar}> <XIcon width='15px' stroke={'#00003C'} /> </CloseXDiv> {pricingTestOn && <RiskReducerContainer> <P fontSize='1.3rem'> <strong> you deserve a little awesome every day <span role='img' aria-label='hearts'>💕</span> </strong> </P> <P fontSize='1.2rem'>Buy 4+ items, get 20% off. always. automatically.</P> </RiskReducerContainer> } <FreeShippingDiv> <FreeShippingText {...this.props} /> <ProgressBar percentage={percentage} /> </FreeShippingDiv> </CartSidebarHeader> <PersistentCartProductList lineItems={lineItems} hideCartSidebar={hideCartSidebar} updateBag={updateBag} removeItem={removeItem} renderProductLink={renderProductLink} segmentCartViewed={segmentCartViewed} /> </div> <Footer> <CouponCodeWrapper promotion={promotion} loading={promotionLoading} promoHasBeenApplied={promoHasBeenApplied} errorMessage={promoErrorMessage} applyPromotion={applyPromotion} removePromotion={removePromotion} appliedPromotion={appliedPromotion} showBorder={false} /> <Total>TOTAL<Em>{accounting.formatMoney(order.total)}</Em></Total> {parseFloat(order.total) > 0 && <Elements> <PaymentRequestButton currentUserEmail={currentUserEmail} order={order} setShippingAddress={setShippingAddress} submitCheckout={this.submitCheckout} onClickPaymentRequestButton={onClickPaymentRequestButton} /> </Elements>} <ButtonLink renderLink={renderLink} target='/checkout' width='100%' maxWidth='30rem' kind='blue' disabled={isCheckoutButtonDisabled} onClick={onClickCheckout}> CHECKOUT </ButtonLink> <CheckoutLink renderLink={renderLink} onClick={hideCartSidebar}>Continue Shopping</CheckoutLink> </Footer> </CartSidebarContainer> </div> ) } } const renderLink = (inProps) => { const {target, children, ...props } = inProps return (<a href={target} {...props}>{children}</a>) } BaseCartSidebar.propTypes = { shouldShowCartSidebar: PropTypes.bool, className: PropTypes.object, hideCartSidebar: PropTypes.func, submitBag: PropTypes.func, subTotal: PropTypes.number, itemsInBag: PropTypes.number, order: PropTypes.object, currentUser: PropTypes.number, submitBagCheckoutStripe: PropTypes.func, loadBag: PropTypes.func, setShippingAddress: PropTypes.func, renderLink: PropTypes.func, updateBag: PropTypes.func, removeItem: PropTypes.func, segmentCartViewed: PropTypes.func, lineItems: PropTypes.array, pricingTestOn: PropTypes.bool, promotion: PropTypes.object, promotionLoading: PropTypes.bool, promoHasBeenApplied: PropTypes.bool, promoErrorMessage: PropTypes.string, applyPromotion: PropTypes.func, removePromotion: PropTypes.func, appliedPromotion: PropTypes.object, renderProductLink: PropTypes.func, currentUserEmail: PropTypes.string } BaseCartSidebar.defaultProps = { renderLink: renderLink, renderProductLink: renderLink, pricingTestOn: true } const CartSidebar = styled(BaseCartSidebar)` width: 100%; position: fixed; right: 0; bottom: 0; top: 0; left: 0; z-index: 70; ` export default CartSidebar