From 7e5de88ee92acafd4e04036957f48a393b939fb6 Mon Sep 17 00:00:00 2001 From: Olha <108747215+OlhaKoziuk@users.noreply.github.com> Date: Wed, 20 Dec 2023 10:18:49 +0200 Subject: [PATCH] create colorCapacityComponent (#55) Co-authored-by: Mykhailo Pogorenyi --- .../ProductDetailsPage/ProductDetailsPage.tsx | 105 +++++++++++++----- .../ColorCapacityComponent.module.scss | 80 +++++++++++++ .../ColorCapacityComponent.tsx | 103 +++++++++++++++++ .../ColorCapacityComponent/index.ts | 1 + src/static/icons/color-icon-dark.svg | 4 + src/static/icons/color-icon.svg | 4 + src/types/Detail.ts | 6 + 7 files changed, 278 insertions(+), 25 deletions(-) create mode 100644 src/modules/ProductDetailsPage/components/ColorCapacityComponent/ColorCapacityComponent.module.scss create mode 100644 src/modules/ProductDetailsPage/components/ColorCapacityComponent/ColorCapacityComponent.tsx create mode 100644 src/modules/ProductDetailsPage/components/ColorCapacityComponent/index.ts create mode 100644 src/static/icons/color-icon-dark.svg create mode 100644 src/static/icons/color-icon.svg create mode 100644 src/types/Detail.ts diff --git a/src/modules/ProductDetailsPage/ProductDetailsPage.tsx b/src/modules/ProductDetailsPage/ProductDetailsPage.tsx index b1cb1f4..4b0e924 100644 --- a/src/modules/ProductDetailsPage/ProductDetailsPage.tsx +++ b/src/modules/ProductDetailsPage/ProductDetailsPage.tsx @@ -1,38 +1,89 @@ import React, { useEffect, useState } from 'react'; -import { useParams } from 'react-router'; - +import { useParams, useNavigate, useLocation } from 'react-router'; import cn from 'classnames'; import styles from './ProductDetailsPage.module.scss'; +import { getRecommendedProducts } from '../../api/service'; +import { useAppSelector } from '../../store/hooks'; +import { Detail, Product } from '../../types/Product'; +import { EndPoints } from '../../types/Enums'; + import { Breadcrumbs } from '../shared/Breadcrumbs'; import { BackButton } from '../shared/BackButton'; import { ProductDetailsSlider } from './components/ProductDetailsSlider'; -import { EndPoints } from '../../types/Enums'; +import { ColorCapacityComponent } from './components/ColorCapacityComponent'; import { ProductAbout } from './components/ProductAbout/ProductAbout'; -import { Detail, Product } from '../../types/Product'; -import { useAppSelector } from '../../store/hooks'; -import { ProductSlider } from '../shared/ProductSlider/ProductSlider'; -import { getRecommendedProducts } from '../../api/service'; import { ProductTechSpec } from './components/ProductTechSpec/ProductTechSpec'; +import { ProductSlider } from '../shared/ProductSlider/ProductSlider'; type Props = { loadData: (endPoint: EndPoints, itemId: string) => Promise; endPoint: EndPoints; }; +function getDetails( + productDetail: Detail, + params: { color: string; capacity: string }, +) { + const { color, capacity } = params; + + if (color && capacity) { + return productDetail.additional.find( + (product) => product.color === color && product.capacity === capacity, + ); + } + + if (color) { + return productDetail.additional.find( + (product) => product.color === color + && product.capacity === productDetail.current.capacity, + ); + } + + if (capacity) { + return productDetail.additional.find( + (product) => product.capacity === capacity + && product.color === productDetail.current.color, + ); + } + + return productDetail.current; +} + export const ProductDetailsPage: React.FC = ({ loadData, endPoint }) => { - const { itemId } = useParams(); - const [productDetail, setProductDetail] = useState(); - const [recommended, setRecommended] = useState([]); const { isDarkTheme } = useAppSelector((state) => state.theme); + const [productDetail, setProductDetail] = useState(null); + const [recommended, setRecommended] = useState([]); + const [color, setColor] = useState(''); + const [capacity, setCapacity] = useState(''); + const { itemId } = useParams(); + const navigate = useNavigate(); + const location = useLocation(); + + const details = productDetail + ? getDetails(productDetail, { color, capacity }) + : null; + + const changeUrl = (id: string) => { + navigate(`/${endPoint}/${id}`, { + replace: true, + state: { ...location.state }, + }); + }; + + useEffect(() => { + if (details) { + changeUrl(details.id); + } + }, [details]); // eslint-disable-line react-hooks/exhaustive-deps useEffect(() => { if (itemId) { loadData(endPoint, itemId).then(setProductDetail); getRecommendedProducts(endPoint, itemId).then(setRecommended); } - }, [loadData, itemId, endPoint, setProductDetail]); + }, []); // eslint-disable-line react-hooks/exhaustive-deps return (
= ({ loadData, endPoint }) => { - {productDetail && ( + {details && ( <> -

- {productDetail.current.name} -

+

{details.name}

+ + - + diff --git a/src/modules/ProductDetailsPage/components/ColorCapacityComponent/ColorCapacityComponent.module.scss b/src/modules/ProductDetailsPage/components/ColorCapacityComponent/ColorCapacityComponent.module.scss new file mode 100644 index 0000000..b5729b7 --- /dev/null +++ b/src/modules/ProductDetailsPage/components/ColorCapacityComponent/ColorCapacityComponent.module.scss @@ -0,0 +1,80 @@ +@import '../../../../styles/utils/mixins/mixin-typography'; +@import '../../../../styles/utils/variables/colors'; +@import '../../../../styles/utils/mixins/mixin-media'; + +.colorCapacity{ + padding-top: 2.5rem; + padding-bottom: 2rem; + display: flex; + flex-direction: column; + gap: 1.5rem; + grid-column: span 4; + + &__DARK { + background-color: $color__dark-theme__black; + } +} + +.content { + display: flex; + justify-content: space-between; + color: $color__secondary; + @include smallText-typography; + + &__DARK { + color: $color__dark-theme__secondary; + } +} + +.contentContainer { + display: flex; + flex-direction: column; + gap: 8px; + padding-bottom: 1.5rem; + border-bottom: 1px solid $color__elements; +} + +.buttonContainer { + display: flex; + gap: 8px; +} + +.colorButton { + width: 32px; + height: 32px; + border: none; + background-color: transparent; + cursor: pointer; +} + +.colorContent { + opacity: 0; +} + +.capacityButton { + padding: 8px 7px 4px; + background-color: transparent; + border-radius: 4px; + border: 1px solid $color__icons; + text-align: center; + color: $color__primary; + cursor: pointer; + @include bodyText-typography; + + &__DARK { + border-color: $color__dark-theme__icons; + color: $color__dark-theme__white; + border-radius: 0; + } + + &__ACTIVE { + border: none; + background-color: $color__primary; + color: $color__white; + + &__DARK { + background-color: $color__dark-theme__white; + color: $color__dark-theme__black; + } + } +} diff --git a/src/modules/ProductDetailsPage/components/ColorCapacityComponent/ColorCapacityComponent.tsx b/src/modules/ProductDetailsPage/components/ColorCapacityComponent/ColorCapacityComponent.tsx new file mode 100644 index 0000000..9303c9d --- /dev/null +++ b/src/modules/ProductDetailsPage/components/ColorCapacityComponent/ColorCapacityComponent.tsx @@ -0,0 +1,103 @@ +import React from 'react'; +import cn from 'classnames'; +import styles from './ColorCapacityComponent.module.scss'; +import { ReactComponent as Color } + from '../../../../static/icons/color-icon.svg'; +import { useAppSelector } from '../../../../store/hooks'; +import { ProductDetail } from '../../../../types/Product'; + +type Props = { + productDetail: ProductDetail; + setColor: React.Dispatch>; + setCapacity: React.Dispatch>; +}; + +export const ColorCapacityComponent: React.FC = ({ + productDetail, + setColor, + setCapacity, +}) => { + const { isDarkTheme } = useAppSelector((state) => state.theme); + + return ( +
+
+ +

+ Available colors +

+ +
+ {isDarkTheme + ? ( + productDetail.colorsAvailable.map(color => ( + + )) + ) + : ( + productDetail.colorsAvailable.map(color => ( + + )) + )} +
+
+ +
+
+ Select capacity +
+
+ {productDetail.capacityAvailable.map(capacity => ( + + ))} +
+
+
+ ); +}; diff --git a/src/modules/ProductDetailsPage/components/ColorCapacityComponent/index.ts b/src/modules/ProductDetailsPage/components/ColorCapacityComponent/index.ts new file mode 100644 index 0000000..831c30b --- /dev/null +++ b/src/modules/ProductDetailsPage/components/ColorCapacityComponent/index.ts @@ -0,0 +1 @@ +export * from './ColorCapacityComponent'; diff --git a/src/static/icons/color-icon-dark.svg b/src/static/icons/color-icon-dark.svg new file mode 100644 index 0000000..9ca9555 --- /dev/null +++ b/src/static/icons/color-icon-dark.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/static/icons/color-icon.svg b/src/static/icons/color-icon.svg new file mode 100644 index 0000000..2512e8c --- /dev/null +++ b/src/static/icons/color-icon.svg @@ -0,0 +1,4 @@ + + + + diff --git a/src/types/Detail.ts b/src/types/Detail.ts new file mode 100644 index 0000000..5c8a24d --- /dev/null +++ b/src/types/Detail.ts @@ -0,0 +1,6 @@ +import { ProductDetail } from './Product'; + +export interface Detail { + current: ProductDetail; + additional: ProductDetail[]; +}