Skip to content

Commit

Permalink
feat(core-components-card-image): add cardImage component (#326)
Browse files Browse the repository at this point in the history
* feat(core-components-card-image): add cardImage component

* refactor(core-components-card-image): remove exceed css properties

* refactor(core-components-card-image): review fixes

* refactor(core-components-card-image): review fixes

* chore(card-image): update story

Co-authored-by: opshilov <opshilov@alfabank.ru>
Co-authored-by: reme3d2y <AYatsenko@alfabank.ru>
  • Loading branch information
3 people committed Nov 27, 2020
1 parent c6644a0 commit 06901af
Show file tree
Hide file tree
Showing 8 changed files with 502 additions and 0 deletions.
19 changes: 19 additions & 0 deletions packages/card-image/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"name": "@alfalab/core-components-card-image",
"version": "1.0.0",
"description": "Card Image component",
"keywords": [],
"license": "ISC",
"main": "dist/index.js",
"files": [
"dist"
],
"publishConfig": {
"access": "public"
},
"peerDependencies": {
"classnames": "^2.2.6",
"react": "^16.9.0",
"react-dom": "^16.9.0"
}
}
54 changes: 54 additions & 0 deletions packages/card-image/src/Component.stories.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { Meta, Story, Props, Preview, Title } from '@storybook/addon-docs/blocks';
import { text, boolean, number } from '@storybook/addon-knobs';
import { Design } from 'storybook/blocks/design';

import { CardImage } from './Component';
import { name, version } from '../package.json';


<Meta title='Компоненты' component={CardImage} />


<!-- Canvas -->

<Story name='CardImage'>
<CardImage
cardId={text('cardId', 'EG')}
layers={text('layers', 'BACKGROUND,CARD_NUMBER,CARD_HOLDER,PAY_PASS,CHIP,LOGO,PAYMENT_SYSTEM,RESERVED_1,RESERVED_2,VALID_DATE')}
width={number('width', 280)}
rounded={boolean('rounded', false)}
baseUrl={text('baseUrl', 'https://online.alfabank.ru/cards-images/cards/')}
/>
</Story>


<!-- Docs -->

<ComponentHeader
name='CardImage'
version={version}
package='@alfalab/core-components-card-image'
stage={1}
/>

```tsx
import { CardImage } from '@alfalab/core-components-card-image';
```

## Описание

Компонент изображения карты.

Показывает прелоадер пока картинка не загрузится (переопределяется через переменную --card-image-background)

<CardImage
cardId='EG'
width={500}
rounded={false}
baseUrl='https://online.alfabank.ru/cards-images/cards/'
className='some name'
id='some id'
dataTestId='test id'
/>

<Props of={CardImage} />
87 changes: 87 additions & 0 deletions packages/card-image/src/Component.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import React from 'react';
import { render } from '@testing-library/react';

import { CardImage, DEFAULT_BASE_URL, DEFAULT_WIDTH, ASPECT_RATIO } from './index';

const layers = 'BACKGROUND,CARD_NUMBER,CARD_HOLDER';
const cardId = 'ER';
describe('CardImage', () => {
describe('Display tests', () => {
it('should display correctly', () => {
expect(render(<CardImage />)).toMatchSnapshot();
});
it('should display with cardId correctly', () => {
expect(render(<CardImage cardId='ER' />)).toMatchSnapshot();
});
it('should display with cardId and layers', () => {
const { container } = render(<CardImage cardId={cardId} layers={layers} />);
const img = container.querySelector('img');
expect(img?.src).toContain(cardId);
expect(img?.src).toContain(`layers=${layers}`);
expect(container).toMatchSnapshot();
});
});

describe('Styles tests', () => {
it('should set custom class', () => {
const className = 'custom-class';
const { container } = render(<CardImage className={className} />);

expect(container.firstElementChild).toHaveClass(className);
});

it('should set `rounded` class', () => {
const { container } = render(<CardImage rounded={true} />);

expect(container.firstElementChild).toHaveClass('rounded');
});
});

describe('Render tests', () => {
test('should unmount without errors', () => {
const { unmount } = render(<CardImage />);

expect(unmount).not.toThrowError();
});

test('should have default baseUrl', () => {
const { container } = render(<CardImage cardId={cardId} layers={layers} />);
const img = container.querySelector('img');
expect(img?.src).toContain(DEFAULT_BASE_URL);
});

test('should have baseUrl', () => {
const baseUrl = 'some-url';
const { container } = render(
<CardImage cardId={cardId} layers={layers} baseUrl={baseUrl} />,
);
const img = container.querySelector('img');
expect(img?.src).toContain(baseUrl);
});

test('should provide custom baseUrl', () => {
const baseUrl = 'some-url';
const { container } = render(
<CardImage cardId={cardId} layers={layers} baseUrl={baseUrl} />,
);
const img = container.querySelector('img');
expect(img?.src).toContain(baseUrl);
});

test('should have default width', () => {
const { container } = render(<CardImage cardId={cardId} layers={layers} />);
const img = container.querySelector('img');
expect(img?.width).toBe(DEFAULT_WIDTH);
});

test('should correctly set height', () => {
const width = 500;
const height = width * ASPECT_RATIO;
const { container } = render(
<CardImage cardId={cardId} layers={layers} width={width} />,
);
const img = container.querySelector('img');
expect(img?.height).toBe(height);
});
});
});
119 changes: 119 additions & 0 deletions packages/card-image/src/Component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import React, { FC, useCallback, useState, useRef } from 'react';
import cn from 'classnames';

import styles from './index.module.css';

export const ASPECT_RATIO = 0.63;
export const DEFAULT_WIDTH = 280;
export const DEFAULT_BASE_URL = 'https://online.alfabank.ru/cards-images/cards/';

export type CardImageProps = {
/**
* Идентификатор карты
* (например: ER, GQ, SU)
*/
cardId?: string;

/**
* Какие слои показывать, через запятую без пробелов
* (полный набор: BACKGROUND,CARD_NUMBER,CARD_HOLDER,PAY_PASS,CHIP,LOGO,PAYMENT_SYSTEM,RESERVED_1,RESERVED_2,VALID_DATE)
*/
layers?: string;

/**
* Ширина изображения
*/
width?: number;

/**
* Скругление углов
*/
rounded?: boolean;

/**
* Базовый URL сервиса с изображениями
*/
baseUrl?: string;

/**
* Колбек, вызываемый при загрузке изображения
*/
onLoad?: () => void;

/**
* Дополнительный класс
*/
className?: string;

/**
* Идентификатор для систем автоматизированного тестирования
*/
alt?: string;

/**
* Уникальный идентификатор блока
*/
id?: string;

/**
* Идентификатор для систем автоматизированного тестирования
*/
dataTestId?: string;
};

export const CardImage: FC<CardImageProps> = ({
cardId,
layers = 'BACKGROUND,CARD_NUMBER,CARD_HOLDER,PAY_PASS,CHIP,LOGO,PAYMENT_SYSTEM,RESERVED_1,RESERVED_2,VALID_DATE',
width = DEFAULT_WIDTH,
baseUrl = DEFAULT_BASE_URL,
rounded = true,
alt,
id,
dataTestId,
onLoad,
className,
}) => {
const [loaded, setLoaded] = useState(false);
const image = useRef<HTMLImageElement>(null);
const height = width * ASPECT_RATIO;
const handleLoadedImage = useCallback(() => {
setLoaded(true);
if (onLoad) {
onLoad();
}
}, [onLoad]);

const cardImageUrl = `${baseUrl}${cardId}/images?layers=${layers}&width=${width}`;
const cardImageUrl2x = `${baseUrl}${cardId}/images?layers=${layers}&width=${width * 2}`;

return (
<div
className={cn(
styles.cardImage,
rounded && styles.rounded,
loaded && styles.loaded,
className,
)}
style={{
width,
height,
}}
id={id}
data-test-id={dataTestId}
>
{cardId && (
<img
ref={image}
className={styles.image}
width={width}
height={height}
src={cardImageUrl}
srcSet={`${cardImageUrl2x} 2x`}
alt={alt}
role='presentation'
onLoad={handleLoadedImage}
/>
)}
</div>
);
};

0 comments on commit 06901af

Please sign in to comment.