diff options
Diffstat (limited to 'src/frontend/components/CartItems')
| -rw-r--r-- | src/frontend/components/CartItems/CartItem.tsx | 40 | ||||
| -rw-r--r-- | src/frontend/components/CartItems/CartItems.styled.ts | 79 | ||||
| -rw-r--r-- | src/frontend/components/CartItems/CartItems.tsx | 82 | ||||
| -rw-r--r-- | src/frontend/components/CartItems/index.ts | 4 |
4 files changed, 205 insertions, 0 deletions
diff --git a/src/frontend/components/CartItems/CartItem.tsx b/src/frontend/components/CartItems/CartItem.tsx new file mode 100644 index 0000000..e78bb7a --- /dev/null +++ b/src/frontend/components/CartItems/CartItem.tsx @@ -0,0 +1,40 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +import Link from 'next/link'; +import { Product } from '../../protos/demo'; +import ProductPrice from '../ProductPrice'; +import * as S from './CartItems.styled'; + +interface IProps { + product: Product; + quantity: number; +} + +const CartItem = ({ + product: { id, name, picture, priceUsd = { units: 0, nanos: 0, currencyCode: 'USD' } }, + quantity, +}: IProps) => { + return ( + <S.CartItem> + <Link href={`/product/${id}`}> + <S.NameContainer> + <S.CartItemImage alt={name} src={"/images/products/" + picture} /> + <p>{name}</p> + </S.NameContainer> + </Link> + <S.CartItemDetails> + <p>{quantity}</p> + </S.CartItemDetails> + <S.CartItemDetails> + <S.PriceContainer> + <p> + <ProductPrice price={priceUsd} /> + </p> + </S.PriceContainer> + </S.CartItemDetails> + </S.CartItem> + ); +}; + +export default CartItem; diff --git a/src/frontend/components/CartItems/CartItems.styled.ts b/src/frontend/components/CartItems/CartItems.styled.ts new file mode 100644 index 0000000..a1a5fbc --- /dev/null +++ b/src/frontend/components/CartItems/CartItems.styled.ts @@ -0,0 +1,79 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +import styled from 'styled-components'; + +export const CartItems = styled.section` + display: flex; + flex-direction: column; +`; + +export const CardItemsHeader = styled.div` + display: grid; + grid-template-columns: 150px 100px auto; + gap: 24px; + + ${({ theme }) => theme.breakpoints.desktop} { + grid-template-columns: 1fr auto auto; + } +`; + +export const CartItemImage = styled.img` + width: 100%; + height: auto; + border-radius: 5px; + + ${({ theme }) => theme.breakpoints.desktop} { + width: 120px; + height: 120px; + } +`; + +export const CartItem = styled.div` + display: grid; + grid-template-columns: 150px 100px auto; + gap: 24px; + padding: 24px 0; + align-items: center; + border-bottom: 1px solid ${({ theme }) => theme.colors.textLightGray}; + + ${({ theme }) => theme.breakpoints.desktop} { + grid-template-columns: 1fr auto auto; + } +`; + +export const CartItemDetails = styled.div` + display: flex; + flex-direction: column; + justify-content: space-between; +`; + +export const NameContainer = styled.div` + display: flex; + align-items: center; + gap: 5px; + flex-direction: column; + cursor: pointer; + + ${({ theme }) => theme.breakpoints.desktop} { + flex-direction: row; + gap: 24px; + } +`; + +export const PriceContainer = styled.div` + display: flex; + width: 100%; + justify-content: space-between; +`; + +export const DataRow = styled.div` + display: flex; + justify-content: flex-end; + padding: 24px 0; + gap: 24px; +`; + +export const TotalText = styled.h3` + margin: 0; +`; diff --git a/src/frontend/components/CartItems/CartItems.tsx b/src/frontend/components/CartItems/CartItems.tsx new file mode 100644 index 0000000..05e0279 --- /dev/null +++ b/src/frontend/components/CartItems/CartItems.tsx @@ -0,0 +1,82 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +import { useMemo } from 'react'; +import { useQuery, UseQueryOptions } from '@tanstack/react-query'; +import ApiGateway from '../../gateways/Api.gateway'; +import { Address, Money } from '../../protos/demo'; +import { useCurrency } from '../../providers/Currency.provider'; +import { IProductCartItem } from '../../types/Cart'; +import ProductPrice from '../ProductPrice'; +import CartItem from './CartItem'; +import * as S from './CartItems.styled'; + +interface IProps { + productList: IProductCartItem[]; + shouldShowPrice?: boolean; +} + +const CartItems = ({ productList, shouldShowPrice = true }: IProps) => { + const { selectedCurrency } = useCurrency(); + const address: Address = { + streetAddress: '1600 Amphitheatre Parkway', + city: 'Mountain View', + state: 'CA', + country: 'United States', + zipCode: '94043', + }; + + const queryKey = ['shipping', productList, selectedCurrency, address]; + const queryFn = () => ApiGateway.getShippingCost(productList, selectedCurrency, address); + const queryOptions: UseQueryOptions<Money, Error> = { + queryKey, + queryFn, + }; + const { data: shippingConst = { units: 0, currencyCode: 'USD', nanos: 0 } } = useQuery(queryOptions); + + const total = useMemo<Money>(() => { + const nanoSum = + productList.reduce((acc, { product: { priceUsd: { nanos = 0 } = {} } }) => acc + Number(nanos), 0) + + shippingConst?.nanos || 0; + const nanoExceed = Math.floor(nanoSum / 1000000000); + + const unitSum = + productList.reduce((acc, { product: { priceUsd: { units = 0 } = {} } }) => acc + Number(units), 0) + + (shippingConst?.units || 0) + nanoExceed; + + return { + units: unitSum, + currencyCode: selectedCurrency, + nanos: nanoSum % 1000000000, + }; + }, [shippingConst?.units, shippingConst?.nanos, productList, selectedCurrency]); + + return ( + <S.CartItems> + <S.CardItemsHeader> + <label>Product</label> + <label>Quantity</label> + <label>Price</label> + </S.CardItemsHeader> + {productList.map(({ productId, product, quantity }) => ( + <CartItem key={productId} product={product} quantity={quantity} /> + ))} + {shouldShowPrice && ( + <> + <S.DataRow> + <span>Shipping</span> + <ProductPrice price={shippingConst} /> + </S.DataRow> + <S.DataRow> + <S.TotalText>Total</S.TotalText> + <S.TotalText> + <ProductPrice price={total} /> + </S.TotalText> + </S.DataRow> + </> + )} + </S.CartItems> + ); +}; + +export default CartItems; diff --git a/src/frontend/components/CartItems/index.ts b/src/frontend/components/CartItems/index.ts new file mode 100644 index 0000000..ad419fa --- /dev/null +++ b/src/frontend/components/CartItems/index.ts @@ -0,0 +1,4 @@ +// Copyright The OpenTelemetry Authors +// SPDX-License-Identifier: Apache-2.0 + +export { default } from './CartItems'; |
