Skip to content

Commit

Permalink
Break summary into components
Browse files Browse the repository at this point in the history
Signed-off-by: Stephen Rugh <[email protected]>
  • Loading branch information
sirugh committed Jan 10, 2020
1 parent ee504c5 commit 9c89db6
Show file tree
Hide file tree
Showing 6 changed files with 250 additions and 225 deletions.
105 changes: 4 additions & 101 deletions packages/peregrine/lib/talons/CartPage/PriceSummary/usePriceSummary.js
Original file line number Diff line number Diff line change
@@ -1,106 +1,10 @@
import { useCallback, useEffect, useMemo } from 'react';
import { useCallback, useEffect } from 'react';
import { useQuery } from '@apollo/react-hooks';
import { useCartContext } from '@magento/peregrine/lib/context/cart';
import isObjectEmpty from '@magento/peregrine/lib/util/isObjectEmpty';

const DEFAULT_AMOUNT = {
currency: 'USD', // TODO: better default
value: 0
};

/**
* Reduces discounts into a single amount.
*
* @param {Array} discounts
*/
const getDiscount = (discounts = []) => {
if (!discounts || !discounts.length) {
return DEFAULT_AMOUNT;
} else {
return {
currency: discounts[0].amount.currency,
value: discounts.reduce(
(acc, discount) => acc + discount.amount.value,
0
)
};
}
};

/**
* Reduces applied tax amounts into a single amount.
*
* @param {Array} applied_taxes
*/
const getEstimatedTax = (applied_taxes = []) => {
if (!applied_taxes.length) {
return DEFAULT_AMOUNT;
} else {
return {
currency: applied_taxes[0].amount.currency,
value: applied_taxes.reduce((acc, tax) => acc + tax.amount.value, 0)
};
}
};

/**
* Reduces applied gift card amounts into a single amount.
*
* @param {Array} cards
*/
const getGiftCards = (cards = []) => {
if (!cards.length) {
return DEFAULT_AMOUNT;
} else {
return {
currency: 'USD',
value: cards.reduce(
(acc, card) => acc + card.applied_balance.value,
0
)
};
}
};

// TODO: I'm confused as to why shipping_addresses is an array. If there are multiple shipping addresses how do we tell which one is the right one?
const getEstimatedShipping = (shipping_addresses = []) => {
if (
!shipping_addresses.length ||
!shipping_addresses[0].selected_shipping_method
) {
return DEFAULT_AMOUNT;
} else {
return shipping_addresses[0].selected_shipping_method.amount;
}
};

const normalizeData = (dataFromGraphQL = {}) => {
if (isObjectEmpty(dataFromGraphQL)) {
return {
subtotal: DEFAULT_AMOUNT,
discount: DEFAULT_AMOUNT,
tax: DEFAULT_AMOUNT,
shipping: DEFAULT_AMOUNT,
total: DEFAULT_AMOUNT
};
}
return {
subtotal: dataFromGraphQL.cart.prices.subtotal_excluding_tax,
// TODO: Coupon value is returned in the `discounts` array but there may be other types of discounts and there is no way to identify them from one another.
// TODO: "discounts" is allowed in 2.3.4, "discount" in 2.3.3, the following is gross but necessary for now since we don't know which gql requested. Could use a static export from the DiscountSummary to name it though.
discount:
dataFromGraphQL.cart.prices.discount ||
getDiscount(dataFromGraphQL.cart.prices.discounts),
giftCard: getGiftCards(dataFromGraphQL.cart.applied_gift_cards),
tax: getEstimatedTax(dataFromGraphQL.cart.prices.applied_taxes),
shipping: getEstimatedShipping(dataFromGraphQL.cart.shipping_addresses),
total: dataFromGraphQL.cart.prices.grand_total
};
};

export const usePriceSummary = props => {
const [{ cartId }] = useCartContext();
const { error, data } = useQuery(props.query, {
const { error, loading, data } = useQuery(props.query, {
variables: {
cartId
},
Expand All @@ -118,12 +22,11 @@ export const usePriceSummary = props => {
}
}, [error]);

const normalizedData = useMemo(() => normalizeData(data), [data]);

return {
handleProceedToCheckout,
hasError: !!error,
hasItems: data && !!data.cart.items.length,
normalizedData
isLoading: !!loading,
data
};
};
Original file line number Diff line number Diff line change
Expand Up @@ -2,53 +2,65 @@ import React from 'react';
import gql from 'fraql';
import { Price } from '@magento/peregrine';

// TODO: v2.3.4 supports "discounts", v2.3.3 supports "discount". Just another place where a build plugin can swap based on schema type availablility
const IS_234 = false;
const DEFAULT_AMOUNT = {
currency: 'USD',
value: 0
};

/**
* Reduces discounts array into a single amount.
*
* @param {Array} discounts
*/
const getDiscount = (discounts = []) => {
if (!discounts || !discounts.length) {
return DEFAULT_AMOUNT;
} else {
return {
currency: discounts[0].amount.currency,
value: discounts.reduce(
(acc, discount) => acc + discount.amount.value,
0
)
};
}
};

/**
* A component that renders the discount summary line item.
*
* @param {Object} props.classes
* @param {Object} props.data query response data
*/
const DiscountSummary = props => {
const { classes, data } = props;
// TODO: useDiscount talon for parsing non-normalized data.
return (
const { classes } = props;
const discount = getDiscount(props.data.cart.prices.discounts);

return discount.value ? (
<>
{data.value ? (
<>
<span className={classes.lineItemLabel}>{'Discount'}</span>
<span className={classes.price}>
{'(-'}
<Price
value={discount.value}
currencyCode={discount.currency}
/>
{')'}
</span>
</>
) : null}
<span className={classes.lineItemLabel}>{'Discounts applied'}</span>
<span className={classes.price}>
{'(-'}
<Price
value={discount.value}
currencyCode={discount.currency}
/>
{')'}
</span>
</>
);
) : null;
};

DiscountSummary.fragments = {
discounts: IS_234
? gql`
fragment _ on CartPrices {
discounts {
amount {
currency
value
}
}
}
`
: gql`
fragment _ on CartPrices {
discount {
amount {
currency
value
}
}
}
`
};
DiscountSummary.fragment = gql`
fragment _ on CartPrices {
discounts {
amount {
currency
value
}
label
}
}
`;

export default DiscountSummary;
Original file line number Diff line number Diff line change
Expand Up @@ -2,49 +2,73 @@ import React from 'react';
import gql from 'fraql';
import { Price } from '@magento/peregrine';

// TODO: Gift cards are only enabled in EE, write a build time tool that turns the component into a no-op and the static fragments into __typename requests.
const IS_EE = false;
const DEFAULT_AMOUNT = {
currency: 'USD', // TODO: better default
value: 0
};

/**
* Reduces applied gift card amounts into a single amount.
*
* @param {Array} cards
*/
const getGiftCards = (cards = []) => {
if (!cards.length) {
return DEFAULT_AMOUNT;
} else {
return {
currency: 'USD',
value: cards.reduce(
(acc, card) => acc + card.applied_balance.value,
0
)
};
}
};

/**
* A component that renders the gift card summary line item.
*
* @param {Object} props.classes
* @param {Object} props.data query response data
*/
const GiftCardSummary = props => {
const { classes, data } = props;
return (
const { classes } = props;

const cards = getGiftCards(props.data.cart.applied_gift_cards);

return cards.value ? (
<>
{data.value ? (
<>
<span className={classes.lineItemLabel}>
{'Gift Card(s) applied'}
</span>
<span className={classes.price}>
{'(-'}
<Price
value={data.value}
currencyCode={data.currency}
/>
{')'}
</span>
</>
) : null}
<span className={classes.lineItemLabel}>
{'Gift Card(s) applied'}
</span>
<span className={classes.price}>
{'(-'}
<Price value={cards.value} currencyCode={cards.currency} />
{')'}
</span>
</>
);
) : null;
};

GiftCardSummary.fragments = {
appliedGiftCards: IS_EE
? gql`
fragment _ on Cart {
applied_gift_cards {
applied_balance {
value
currency
}
// TODO: Gift cards are only enabled in EE, write a build time tool that turns the component into a no-op and the static fragments into __typename requests.
const IS_EE = false;

GiftCardSummary.fragment = IS_EE
? gql`
fragment _ on Cart {
applied_gift_cards {
applied_balance {
value
currency
}
}
`
: gql`
fragment _ on Cart {
__typename
}
`
};
}
`
: gql`
fragment _ on Cart {
__typename
}
`;

export default GiftCardSummary;
Loading

0 comments on commit 9c89db6

Please sign in to comment.