All files / app/checkout getCheckoutStepStatuses.ts

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144  4x 4x   4x 4x 4x 4x   4x   4x 77x 77x 77x   63x 63x 63x 63x   63x                   4x 77x 77x 77x 77x   77x     58x 58x 58x 58x   58x 47x 5x 5x   5x                 53x                   4x 77x 77x 77x 77x 77x 77x   77x   77x   58x   58x 58x 58x 58x 58x   58x                   4x 77x   5x   5x                   4x           75x             127x   75x 300x   300x                   4x  
import { CheckoutSelectors } from '@bigcommerce/checkout-sdk';
import { compact } from 'lodash';
import { createSelector } from 'reselect';
 
import { isValidAddress } from '../address';
import { EMPTY_ARRAY } from '../common/utility';
import { SUPPORTED_METHODS } from '../customer';
import { hasSelectedShippingOptions, hasUnassignedLineItems, itemsRequireShipping } from '../shipping';
 
import CheckoutStepType from './CheckoutStepType';
 
const getCustomerStepStatus = createSelector(
    ({ data }: CheckoutSelectors) => data.getCheckout(),
    ({ data }: CheckoutSelectors) => data.getCustomer(),
    ({ data }: CheckoutSelectors) => data.getBillingAddress(),
    (checkout, customer, billingAddress) => {
        const hasEmail = !!(customer && customer.email || billingAddress && billingAddress.email);
        const isUsingWallet = checkout && checkout.payments ? checkout.payments.some(payment => SUPPORTED_METHODS.indexOf(payment.providerId) >= 0) : false;
        const isGuest = !!(customer && customer.isGuest);
        const isComplete = hasEmail || isUsingWallet;
 
        return {
            type: CheckoutStepType.Customer,
            isActive: false,
            isComplete,
            isEditable: isComplete && !isUsingWallet && isGuest,
            isRequired: true,
        };
    }
);
 
const getBillingStepStatus = createSelector(
    ({ data }: CheckoutSelectors) => data.getCheckout(),
    ({ data }: CheckoutSelectors) => data.getBillingAddress(),
    ({ data }: CheckoutSelectors) => {
        const billingAddress = data.getBillingAddress();
 
        return billingAddress ? data.getBillingAddressFields(billingAddress.countryCode) : EMPTY_ARRAY;
    },
    (checkout, billingAddress, billingAddressFields) => {
        const hasAddress = billingAddress ? isValidAddress(billingAddress, billingAddressFields) : false;
        const isUsingWallet = checkout && checkout.payments ? checkout.payments.some(payment => SUPPORTED_METHODS.indexOf(payment.providerId) >= 0) : false;
        const isComplete = hasAddress || isUsingWallet;
        const isUsingAmazonPay = checkout && checkout.payments ? checkout.payments.some(payment => payment.providerId === 'amazonpay') : false;
 
        if (isUsingAmazonPay) {
            const billingAddressCustomFields = billingAddressFields.filter(({ custom }: { custom: boolean }) => custom);
            const hasCustomFields = billingAddressCustomFields.length > 0;
            const isAmazonPayBillingStepComplete = billingAddress && hasCustomFields ? isValidAddress(billingAddress, billingAddressCustomFields) : true;
 
            return {
                type: CheckoutStepType.Billing,
                isActive: false,
                isComplete: isAmazonPayBillingStepComplete,
                isEditable: isAmazonPayBillingStepComplete && hasCustomFields,
                isRequired: true,
            };
        }
 
        return {
            type: CheckoutStepType.Billing,
            isActive: false,
            isComplete,
            isEditable: isComplete && !isUsingWallet,
            isRequired: true,
        };
    }
);
 
const getShippingStepStatus = createSelector(
    ({ data }: CheckoutSelectors) => data.getShippingAddress(),
    ({ data }: CheckoutSelectors) => data.getConsignments(),
    ({ data }: CheckoutSelectors) => data.getCart(),
    ({ data }: CheckoutSelectors) => data.getSelectedPaymentMethod(),
    ({ data }: CheckoutSelectors) => {
        const shippingAddress = data.getShippingAddress();
 
        return shippingAddress ? data.getShippingAddressFields(shippingAddress.countryCode) : EMPTY_ARRAY;
    },
    ({ data }: CheckoutSelectors) => data.getConfig(),
    (shippingAddress, consignments, cart, payment, shippingAddressFields, config) => {
        const hasAddress = shippingAddress ? isValidAddress(shippingAddress, shippingAddressFields) : false;
        // @todo: interim solution, ideally we should render custom form fields below amazon shipping widget
        const hasRemoteAddress = !!shippingAddress && !!payment && payment.id === 'amazon';
        const hasOptions = consignments ? hasSelectedShippingOptions(consignments) : false;
        const hasUnassignedItems = cart && consignments ? hasUnassignedLineItems(consignments, cart.lineItems) : true;
        const isComplete = (hasAddress || hasRemoteAddress) && hasOptions && !hasUnassignedItems;
        const isRequired = itemsRequireShipping(cart, config);
 
        return {
            type: CheckoutStepType.Shipping,
            isActive: false,
            isComplete,
            isEditable: isComplete && isRequired,
            isRequired,
        };
    }
);
 
const getPaymentStepStatus = createSelector(
    ({ data }: CheckoutSelectors) => data.getOrder(),
    order => {
        const isComplete = order ? order.isComplete : false;
 
        return {
            type: CheckoutStepType.Payment,
            isActive: false,
            isComplete,
            isEditable: isComplete,
            isRequired: true,
        };
    }
);
 
const getCheckoutStepStatuses = createSelector(
    getCustomerStepStatus,
    getShippingStepStatus,
    getBillingStepStatus,
    getPaymentStepStatus,
    (customerStep, shippingStep, billingStep, paymentStep) => {
        const steps = compact([
            customerStep,
            shippingStep,
            billingStep,
            paymentStep,
        ]);
 
        const defaultActiveStep = steps.find(step => !step.isComplete && step.isRequired) || steps[steps.length - 1];
 
        return steps.map((step, index) => {
            const isPrevStepComplete = steps.slice(0, index).every(prevStep => prevStep.isComplete || !prevStep.isRequired);
 
            return {
                ...step,
                isActive: defaultActiveStep.type === step.type,
                // A step is only editable if its previous step is complete or not required
                isEditable: isPrevStepComplete && step.isEditable,
            };
        });
    }
);
 
export default getCheckoutStepStatuses;