Skip to content

Commit

Permalink
create colorCapacityComponent (#55)
Browse files Browse the repository at this point in the history
Co-authored-by: Mykhailo Pogorenyi <mpohorenyi@gmail.com>
  • Loading branch information
OlhaKoziuk and mpohorenyi authored Dec 20, 2023
1 parent d76b77b commit 7e5de88
Show file tree
Hide file tree
Showing 7 changed files with 278 additions and 25 deletions.
105 changes: 80 additions & 25 deletions src/modules/ProductDetailsPage/ProductDetailsPage.tsx
Original file line number Diff line number Diff line change
@@ -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<Detail>;
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<Props> = ({ loadData, endPoint }) => {
const { itemId } = useParams();
const [productDetail, setProductDetail] = useState<Detail>();
const [recommended, setRecommended] = useState<Product[]>([]);
const { isDarkTheme } = useAppSelector((state) => state.theme);
const [productDetail, setProductDetail] = useState<Detail | null>(null);
const [recommended, setRecommended] = useState<Product[]>([]);
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 (
<section
Expand All @@ -44,30 +95,34 @@ export const ProductDetailsPage: React.FC<Props> = ({ loadData, endPoint }) => {

<BackButton />

{productDetail && (
{details && (
<>
<h2 className={styles.productDetails__title}>
{productDetail.current.name}
</h2>
<h2 className={styles.productDetails__title}>{details.name}</h2>

<ProductDetailsSlider images={details.images} />

<ProductDetailsSlider images={productDetail.current.images} />
<ColorCapacityComponent
productDetail={details}
setColor={setColor}
setCapacity={setCapacity}
/>

<ProductAbout
isDarkTheme={isDarkTheme}
description={productDetail.current.description}
description={details.description}
/>

<ProductTechSpec
isDarkTheme={isDarkTheme}
specs={{
screen: productDetail.current.screen,
resolution: productDetail.current.resolution,
processor: productDetail.current.processor,
ram: productDetail.current.ram,
'built in memory': productDetail.current.capacity,
camera: productDetail.current.camera,
zoom: productDetail.current.zoom,
cell: productDetail.current.cell,
screen: details.screen,
resolution: details.resolution,
processor: details.processor,
ram: details.ram,
'built in memory': details.capacity,
camera: details.camera,
zoom: details.zoom,
cell: details.cell,
}}
/>

Expand Down
Original file line number Diff line number Diff line change
@@ -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;
}
}
}
Original file line number Diff line number Diff line change
@@ -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<React.SetStateAction<string>>;
setCapacity: React.Dispatch<React.SetStateAction<string>>;
};

export const ColorCapacityComponent: React.FC<Props> = ({
productDetail,
setColor,
setCapacity,
}) => {
const { isDarkTheme } = useAppSelector((state) => state.theme);

return (
<section
className={cn(styles.colorCapacity, {
[styles.colorCapacity__DARK]: isDarkTheme,
})}
>
<div className={styles.contentContainer}>

<p
className={cn(styles.content, {
[styles.content__DARK]: isDarkTheme,
})}
>
Available colors
</p>

<div className={styles.buttonContainer}>
{isDarkTheme
? (
productDetail.colorsAvailable.map(color => (
<button
type="button"
key={color}
className={styles.colorButton}
onClick={(event) => setColor(event.currentTarget.innerText)}
>
<Color
color={color}
stroke={color === productDetail.color
? '#f1f2f9' : '#3b3e4a'}
/>
<p className={styles.colorContent}>{color}</p>
</button>
))
)
: (
productDetail.colorsAvailable.map(color => (
<button
type="button"
key={color}
className={styles.colorButton}
onClick={(event) => setColor(event.currentTarget.innerText)}
>
<Color
color={color}
stroke={color === productDetail.color
? '#0f0f11' : '#e2e6e9'}
/>
<p className={styles.colorContent}>{color}</p>
</button>
))
)}
</div>
</div>

<div className={styles.contentContainer}>
<h5 className={styles.content}>
Select capacity
</h5>
<div className={styles.buttonContainer}>
{productDetail.capacityAvailable.map(capacity => (
<button
type="button"
key={capacity}
className={cn(styles.capacityButton, {
[styles.capacityButton__ACTIVE]:
capacity === productDetail.capacity,
[styles.capacityButton__DARK]: isDarkTheme,
[styles.capacityButton__ACTIVE__DARK]:
isDarkTheme && capacity === productDetail.capacity,

})}
onClick={(event) => setCapacity(event.currentTarget.innerText)}
>
<p>{capacity}</p>
</button>
))}
</div>
</div>
</section>
);
};
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './ColorCapacityComponent';
4 changes: 4 additions & 0 deletions src/static/icons/color-icon-dark.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions src/static/icons/color-icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions src/types/Detail.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { ProductDetail } from './Product';

export interface Detail {
current: ProductDetail;
additional: ProductDetail[];
}

0 comments on commit 7e5de88

Please sign in to comment.