Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RUC - 63 wishlist and CartIcon components #67

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/App.scss
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,7 @@
.firstSelect {
z-index: 1;
}

.wishlist {
width: 50%;
}
23 changes: 23 additions & 0 deletions src/common/mocks/wishlistProducts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
export default [
{
name: 'Blue summer hat',
price: '25.00 EUR',
image: 'https://cdn.pixabay.com/photo/2015/10/13/03/39/fashion-985556_1280.jpg',
id: '1',
// inCartCount: 0,
},
{
name: 'Huge sombrero',
price: '30.99 EUR',
image: 'https://cdn.pixabay.com/photo/2015/12/08/01/04/sombrero-1082322_1280.jpg',
id: '2',
// inCartCount: 0,
},
{
name: 'Hunter hat',
price: '23.50 EUR',
image: 'https://cdn.pixabay.com/photo/2016/11/18/14/15/forest-1834831_1280.jpg',
id: '3',
inCartCount: 0,
}
]
36 changes: 21 additions & 15 deletions src/components/atoms/Text/Text.tsx
Original file line number Diff line number Diff line change
@@ -1,24 +1,30 @@
import React from 'react';
import styled from 'styled-components';
import { COLOR_OPTIONS, TEXT_ALIGNMENT_OPTIONS, FONT_WEIGHT_OPTIONS } from '../../../common/constants/consts';
import {
COLOR_OPTIONS,
TEXT_ALIGNMENT_OPTIONS,
FONT_WEIGHT_OPTIONS,
} from '../../../common/constants/consts';

interface IText {
export type FontWeights =
| 'normal'
| 'bold'
| '100'
| '200'
| '300'
| '400'
| '500'
| '600'
| '700'
| '800'
| '900';

export interface IText {
className?: string;
children: string;
children?: string;
color?: string;
fontColor?: string;
fontWeight?:
| 'normal'
| 'bold'
| '100'
| '200'
| '300'
| '400'
| '500'
| '600'
| '700'
| '800'
| '900';
fontWeight?: FontWeights;
lineHeight?: number;
fontSize?: number;
textAlign?: 'left' | 'right' | 'center' | 'justify';
Expand Down
69 changes: 69 additions & 0 deletions src/components/molecules/CartIcon/CartIcon.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
import React from 'react';
import { create, act } from 'react-test-renderer';
import 'jest-styled-components';
import { ThemeProvider } from 'styled-components';
import theme from '../../../common/theme';
import CartIcon from './CartIcon';
import Badge from '../../atoms/Badge/Badge';

describe('Cart Icon component', () => {
it('should render correctly', () => {
const cartIcon = create(
<ThemeProvider theme={theme}>
<CartIcon />
</ThemeProvider>
).toJSON();
expect(cartIcon).toMatchSnapshot();
})

it('should render icon in default theme color and default size', () => {
const tree = create(
<ThemeProvider theme={theme}>
<CartIcon />
</ThemeProvider>
).toJSON();
const cartIcon = tree.children[0];
expect(cartIcon).toHaveStyleRule('background-color', '#000000');
expect(cartIcon).toHaveStyleRule('color', '#ffffff');
expect(cartIcon).toHaveStyleRule('width', '40px');
});

it('should render icon in custom colors', () => {
const tree = create(
<ThemeProvider theme={theme}>
<CartIcon backgroundColor="red" fontColor="blue" width={30} />
</ThemeProvider>
).toJSON();
const cartIcon = tree.children[0];
expect(cartIcon).toHaveStyleRule('background-color', 'red');
expect(cartIcon).toHaveStyleRule('color', 'blue');
expect(cartIcon).toHaveStyleRule('width', '30px');
})

it('should render with product number label', () => {
const cartIcon = create(
<ThemeProvider theme={theme}>
<CartIcon numberOfItemsInCart={3} />
</ThemeProvider>
)
const instance = cartIcon.root;
const badge = instance.findByType(Badge).findByType('span');
expect(badge.props.children).toBe(3);
})

it('should call onClick method', () => {
const mockFn = jest.fn();
const e = { stopPropagation: jest.fn() };
const cartIcon = create(
<ThemeProvider theme={theme}>
<CartIcon onCartIconClick={mockFn} />
</ThemeProvider>
)
const instance = cartIcon.root;
const icon = instance.findByType('svg');
act(() => {
icon.props.onClick(e);
})
expect(mockFn.mock.calls.length).toEqual(1);
})
});
129 changes: 129 additions & 0 deletions src/components/molecules/CartIcon/CartIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
import React from 'react';
import styled from 'styled-components';
import { CartPlus } from '@styled-icons/fa-solid/CartPlus';
import Badge from '../../atoms/Badge/Badge';
import { COLOR_OPTIONS } from '../../../common/constants/consts';
import './cartIcon.scss';

interface ICartIconContainerStyle {
width?: number;
hideCartNumberLabel?: boolean;
}

interface ICartIcon extends ICartIconContainerStyle {
color?: string;
isActive?: boolean;
backgroundColor?: string;
fontColor?: string;
scaleOnHover?: boolean;
}

export interface ICartIconContainer extends ICartIcon {
className?: string;
onCartIconClick?: (product?: any) => void;
numberOfItemsInCart?: number;
}

const defaultProps = {
color: COLOR_OPTIONS.primary,
width: 40,
hideCartNumberLabel: false,
numberOfItemsInCart: 0,
isActive: false,
scaleOnHover: false,
};

export const StyledCartIcon = styled(CartPlus)<ICartIcon>`
${({
theme,
color = defaultProps.color,
isActive,
fontColor,
backgroundColor,
width = defaultProps.width,
scaleOnHover = defaultProps.scaleOnHover,
}) => ({
color: fontColor || theme.colors[color].light,
'background-color': backgroundColor || theme.colors[color].base,
width: `${width}px`,
padding: '7px',
'border-radius': '5px',
transition: 'transform .2s',
transform: isActive && !scaleOnHover ? 'scale(1.2)' : 'scale(1)',
cursor: 'pointer',
'&:hover': {
transform: scaleOnHover ? 'scale(1.2)' : 'scale(1)',
},
})}
`;

const CartIconWrapper = styled.div<ICartIconContainerStyle>`
${({ width = defaultProps.width, hideCartNumberLabel = defaultProps.hideCartNumberLabel }) => ({
height: hideCartNumberLabel ? `${width}px` : `${width + 25}px`,
width: hideCartNumberLabel ? `${width}px` : `${width + 25}px`,
})}
`;

const CartIcon = ({
color,
isActive,
onCartIconClick,
hideCartNumberLabel,
numberOfItemsInCart,
className,
fontColor,
backgroundColor,
width,
scaleOnHover,
}: ICartIconContainer) => {
const handleOnCartIconClick = (e: React.MouseEvent, product: any) => {
e.stopPropagation();
onCartIconClick && onCartIconClick(product);
};

if (hideCartNumberLabel || numberOfItemsInCart === 0) {
return (
<CartIconWrapper
className={className}
width={width}
hideCartNumberLabel={hideCartNumberLabel}
>
<StyledCartIcon
color={color}
isActive={isActive}
onClick={(e: React.MouseEvent, product?: any) => {
handleOnCartIconClick(e, product);
}}
className="cartIconContainer--nolabel"
fontColor={fontColor}
backgroundColor={backgroundColor}
width={width}
scaleOnHover={scaleOnHover}
/>
</CartIconWrapper>
);
}
return (
<CartIconWrapper className={className} width={width}>
<div className="cartIconContainer--label">
<Badge badgeContent={numberOfItemsInCart} color={color}>
<StyledCartIcon
color={color}
isActive={isActive}
onClick={(e: React.MouseEvent, product?: any) => {
handleOnCartIconClick(e, product);
}}
fontColor={fontColor}
backgroundColor={backgroundColor}
width={width}
scaleOnHover={scaleOnHover}
/>
</Badge>
</div>
</CartIconWrapper>
);
};

CartIcon.defaultProps = defaultProps;

export default CartIcon;
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Cart Icon component should render correctly 1`] = `
.c1 {
display: inline-block;
vertical-align: -.125em;
overflow: hidden;
}

.c2 {
color: #ffffff;
background-color: #000000;
width: 40px;
padding: 7px;
border-radius: 5px;
-webkit-transition: -webkit-transform .2s;
-webkit-transition: transform .2s;
transition: transform .2s;
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
cursor: pointer;
}

.c2:hover {
-webkit-transform: scale(1);
-ms-transform: scale(1);
transform: scale(1);
}

.c0 {
position: relative;
height: 65px;
width: 65px;
}

<div
className="c0"
width={40}
>
<svg
aria-hidden="true"
className="c1 c2 cartIconContainer--nolabel"
color="primary"
fill="currentColor"
focusable="false"
onClick={[Function]}
viewBox="0 0 576 512"
width={40}
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M504.717 320H211.572l6.545 32h268.418c15.401 0 26.816 14.301 23.403 29.319l-5.517 24.276C523.112 414.668 536 433.828 536 456c0 31.202-25.519 56.444-56.824 55.994-29.823-.429-54.35-24.631-55.155-54.447-.44-16.287 6.085-31.049 16.803-41.548H231.176C241.553 426.165 248 440.326 248 456c0 31.813-26.528 57.431-58.67 55.938-28.54-1.325-51.751-24.385-53.251-52.917-1.158-22.034 10.436-41.455 28.051-51.586L93.883 64H24C10.745 64 0 53.255 0 40V24C0 10.745 10.745 0 24 0h102.529c11.401 0 21.228 8.021 23.513 19.19L159.208 64H551.99c15.401 0 26.816 14.301 23.403 29.319l-47.273 208C525.637 312.246 515.923 320 504.717 320zM408 168h-48v-40c0-8.837-7.163-16-16-16h-16c-8.837 0-16 7.163-16 16v40h-48c-8.837 0-16 7.163-16 16v16c0 8.837 7.163 16 16 16h48v40c0 8.837 7.163 16 16 16h16c8.837 0 16-7.163 16-16v-40h48c8.837 0 16-7.163 16-16v-16c0-8.837-7.163-16-16-16z"
fill="currentColor"
/>
</svg>
</div>
`;
14 changes: 14 additions & 0 deletions src/components/molecules/CartIcon/cartIcon.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
.cartIconContainer--label {
position: absolute;
bottom: -12px;
left: -10px;
div {
margin: 0;
}
}

.cartIconContainer--nolabel {
position: absolute;
bottom: 0;
left: 0;
}
Loading