Skip to content
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
1,650 changes: 1,622 additions & 28 deletions package-lock.json

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@
"eslint-plugin-react-hooks": "^4.6.0",
"husky": "^7.0.4",
"lint-staged": "^12.4.1",
"msw": "^1.2.1",
"prettier": "2.8.4"
}
}
122 changes: 30 additions & 92 deletions src/components/card/card.scss
Original file line number Diff line number Diff line change
@@ -1,120 +1,70 @@
@import '../../scss/constants.scss';

:root {
--border-radius-card: 16px;
--padding-card: 15px;
--aspect-ratio-card: 1/1;
--overlay-direction: 0deg;
--overlay-color: rgba(0, 0, 0, 0);
--card-text-shadow: none;
--gap-card: 10px;
--radius-button: 9px;
--color-button: #6d7bf8;
--aspect-ratio-image: 4/3;
--justify-content-value: flex-end;
--align-items-value: stretch;
--text-align-value: start;
--margin-top-subtitle: 0;
--margin-inline-value: auto;
}

.card {
.card-item {
position: relative;
font-family: 'Rubik', sans-serif;
display: flex;
flex-direction: column;
justify-content: var(--justify-content-value);
align-items: var(--align-items-value);
min-height: 254px;
justify-content: flex-end;
min-height: 530px; // 2/3 280*420 +h110
width: 280px;
border-radius: var(--border-radius-card);
border-radius: $border-radius-small;
box-shadow: 0 0 7px 3px rgba(0, 0, 0, 0.1);
text-align: center;
background-color: $light-color-1;
overflow: hidden;
box-shadow: 0 0 7px 3px rgba(0, 0, 0, 0.09);
aspect-ratio: var(--aspect-ratio-card);
text-align: var(--text-align-value);

background-color: #fff;
}

.card-content {
z-index: 1;
text-shadow: var(--card-text-shadow);
padding: var(--padding-card);
.card-item__image {
position: absolute;
top: 0;
right: 0;
left: 0;
height: 420px;
background-color: $gray-light-color;
}

.card-image {
// aspect-ratio: 2/3; 300:450
.card-item__image img {
display: block;
max-width: 100%;
object-fit: cover;
width: 100%;
height: 100%;
aspect-ratio: var(--aspect-ratio-image);
}

.card-content-wrapper {
display: block !important;
.card-item__content {
z-index: 1;
padding: 10px;
text-align: center;
}

.card-side {
margin-inline: var(--margin-inline-value);
}

.card-title {
color: #222;
}

.card-subtitle {
display: block;
font-weight: 400;
color: #5a5a5a;
}

.card-side > * + * {
margin-top: var(--gap-card) !important;
}

.card-content-wrapper .card-button {
margin-inline: var(--margin-inline-value);
}

.stacked .card-content {
text-shadow: revert !important;
.card-item__title-container {
display: flex;
align-items: center;
justify-content: space-between;
justify-content: center;
gap: 5px;
margin: 0 0 5px 0;
}

.card-content .card-title {
.card-item__title {
color: #222;
font-weight: 700;
font-size: 20px;
margin: 0;
font-size: 18px;
}

.card-content .card-subtitle {
.card-item__year {
font-weight: 400;
display: block;
font-size: 18px;
color: #5a5a5a;
font-style: normal;
margin-top: var(--margin-top-subtitle);
}

.card-button {
display: block;
margin-inline: auto;
border: none;
background: var(--color-button);
color: white;
padding: 8px 16px;
border-radius: var(--radius-button);
cursor: pointer;
.card-item__button {
text-align: center;
}

.tag {
position: absolute;
top: 24px;
background: #e7e9fe;
background: $accent2-color;
color: $text-color-light;
padding: 8px 16px;
Expand All @@ -129,16 +79,4 @@
right: 0;
border-top-left-radius: 5px;
border-bottom-left-radius: 5px;
}

.dropdown-button {
border: none;
background-color: transparent;
cursor: pointer;
}

.card-price {
color: $accent1-color;
font-weight: 700;
font-size: 22px;
}
}
29 changes: 10 additions & 19 deletions src/components/card/card.test.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,19 @@
import { render, screen } from '@testing-library/react';

import Card from './card';
import { dataMovie } from '../../data/dataMovie';

describe('test Card component', () => {
const product = {
id: 22,
title: 'Elbow Macaroni - 400 gm',
description: 'Product details of Bake Parlor Big Elbow Macaroni - 400 gm',
price: 14,
discountPercentage: 15.58,
rating: 4.57,
stock: 146,
brand: 'Bake Parlor Big',
category: 'groceries',
thumbnail: 'https://i.dummyjson.com/data/products/22/thumbnail.jpg',
images: [
'https://i.dummyjson.com/data/products/22/1.jpg',
'https://i.dummyjson.com/data/products/22/2.jpg',
'https://i.dummyjson.com/data/products/22/3.jpg',
],
};
const mockFunction = jest.fn();

test('it renders', () => {
render(<Card product={product} />);
expect(screen.getByText(/Elbow Macaroni/i)).toBeInTheDocument();
render(<Card item={dataMovie} setIsModalOpen={mockFunction} showDetailInfo={mockFunction} />);
expect(screen.getByRole('card-item')).toBeInTheDocument();
});

test('it renders title of film "Fight Club", release-year "1999"', () => {
render(<Card item={dataMovie} setIsModalOpen={mockFunction} showDetailInfo={mockFunction} />);
expect(screen.getByText(/Fight Club/i)).toBeInTheDocument();
expect(screen.getByText(/1999/i)).toBeInTheDocument();
});
});
44 changes: 29 additions & 15 deletions src/components/card/card.tsx
Original file line number Diff line number Diff line change
@@ -1,28 +1,42 @@
import React from 'react';

import './card.scss';
import { IProduct } from '../types';
import { IMovie } from '../types';
import { _baseImagePath } from '../../services/movies-services';

type CardProps = { product: IProduct };
type CardProps = {
item: IMovie;
setIsModalOpen: (newValue: boolean) => void;
showDetailInfo: (id: number) => void;
};

const Card = ({ item, setIsModalOpen, showDetailInfo }: CardProps) => {
const { id, title, original_title, poster_path, vote_average, release_date } = item;
const baseImagePath = _baseImagePath;
const yearRelease: string = release_date.slice(0, 4);

const Card = (props: CardProps) => {
const { product } = props;
const { title, brand, images, price } = product;
const showMoreInfo = () => {
setIsModalOpen(true);
showDetailInfo(id);
};

return (
<article className='card stacked'>
<div className='image-wrap'>
<img className='card-image' src={images[0]} alt='image' />
<article className='card-item' role='card-item'>
<div className='card-item__image'>
<img src={`https://${baseImagePath}${poster_path}`} alt='poster of film' />
</div>
<div className='card-content card-content-wrapper'>
<div className='card-side card-content-button'>
<h2 className='card-title'>{title}</h2>
<div className='card-price'>{price}$</div>
<cite className='card-subtitle'>{brand}</cite>
<button className='card-button'>Learn more</button>
<div className='card-item__content'>
<div className='card-item__title-container'>
<h2 className='card-item__title'>
{original_title ? original_title : title}
<span className='card-item__year'>{`, ${yearRelease}`}</span>
</h2>
</div>
<button className='card-item__button btn' onClick={showMoreInfo} role='showMoreInfo-button'>
Learn more
</button>
</div>
<span className='tag top-left'>Top</span>
<span className='tag top-left'>{vote_average}</span>
</article>
);
};
Expand Down
2 changes: 1 addition & 1 deletion src/components/cards-list/cards-list.scss
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
.cards-list {
display: flex;
justify-content: space-between;
justify-content: center;
gap: 10px;
flex-wrap: wrap;
margin: 20px 0;
Expand Down
13 changes: 10 additions & 3 deletions src/components/cards-list/cards-list.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,22 @@ import React from 'react';
import { render, screen, waitFor } from '@testing-library/react';

import CardsList from './cards-list';
import { dataGoods } from '../../data/data';
import { dataMovie } from '../../data/dataMovie';
import { IMovie } from '../types';

describe('test CardsList component', () => {
const products = dataGoods.products.slice(8, 16);
const itemsMoke: IMovie[] = [dataMovie, dataMovie];
const mockFunction = jest.fn();

test('it renders', async () => {
render(<CardsList products={products} />);
render(<CardsList items={itemsMoke} setIsModalOpen={mockFunction} showDetailInfo={mockFunction} />);

const cardsList = await waitFor(() => screen.getByTestId('cards-list'));
expect(cardsList).toBeInTheDocument();
});

test('should be render all Card in CardsList ', () => {
render(<CardsList items={itemsMoke} setIsModalOpen={mockFunction} showDetailInfo={mockFunction} />);
expect(screen.getAllByRole('card-item').length).toBe(itemsMoke.length);
});
});
14 changes: 8 additions & 6 deletions src/components/cards-list/cards-list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,21 @@ import React from 'react';
import './cards-list.scss';

import Card from '../card';
import { IProduct } from '../types';
import { IMovie } from '../types';

type CardListProps = {
products: IProduct[];
items: IMovie[];
setIsModalOpen: (newValue: boolean) => void;
showDetailInfo: (id: number) => void;
};

const CardList = ({ products }: CardListProps) => {
const cards = products.map((product) => {
const { id } = product;
const CardList = ({ items, setIsModalOpen, showDetailInfo }: CardListProps) => {
const cards = items.map((item) => {
const { id } = item;

return (
<li key={id} className='cards-list__item'>
<Card product={product} />
<Card item={item} setIsModalOpen={setIsModalOpen} showDetailInfo={showDetailInfo} />
</li>
);
});
Expand Down
20 changes: 20 additions & 0 deletions src/components/detailInfo/detailInfo.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
@import '../../scss/constants.scss';

.detail-info {
&__title {
font-size: 20px;
font-weight: 700;
color: $accent1-color;
margin: 0 50px 10px;
}

&__subtitle {
font-size: 18px;
font-weight: 700;
color: $gray-color;
margin: 0 0 10px;
}

&__homepage {
}
}
27 changes: 27 additions & 0 deletions src/components/detailInfo/detailInfo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import React from 'react';

import './detailInfo.scss';
import { IMovie } from '../types';

type DetailInfoProps = {
info: IMovie | null;
};

const DetailInfo = ({ info }: DetailInfoProps) => {
const { overview, title, homepage } = info!;

return (
<div className='detail-info' data-testid='detail-info'>
<h3 className='detail-info__title'>{title}</h3>
<div className='detail-info__subtitle'>overview</div>
<p>{overview}</p>
{homepage && (
<a className='detail-info__homepage btn btn--col-5' href={homepage}>
Homepage movie
</a>
)}
</div>
);
};

export default DetailInfo;
1 change: 1 addition & 0 deletions src/components/detailInfo/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default } from './detailInfo';
Loading