-
Notifications
You must be signed in to change notification settings - Fork 45
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(core-components-card-image): add cardImage component (#326)
* 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
1 parent
c6644a0
commit 06901af
Showing
8 changed files
with
502 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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} /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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> | ||
); | ||
}; |
Oops, something went wrong.