-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: TET-853 add FileItem component (#143)
* feat: TET-853 add FileItem component * feat: TET-853 tests for files services * fix: TET-853 remove unused import * refactor: TET-853 FileItem styles cleanup * fix: TET-853 decrease padding of compressed variant buttons * refactor: TET-853 unify props of internal FileItem components * refactor: TET-853 remove redundant properties from FileItem story * refactor: TET-853 use -width-small instead -width-100 * fix: TET-853 appropriate dot * refactor: TET-853 introduce flexbox to ensure accuracy between text and dot
- Loading branch information
1 parent
db37e79
commit 9f50c5e
Showing
30 changed files
with
1,381 additions
and
1 deletion.
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,23 @@ | ||
import { FileItemConfig } from './FileItem.styles'; | ||
import { FileItemState, FileItemThumbnail, FileItemCommonProps } from './types'; | ||
|
||
export type FileItemProps = FileItemCommonProps & { | ||
custom?: FileItemConfig; | ||
isExtended?: boolean; | ||
thumbnail?: FileItemThumbnail; | ||
timeLeftText?: string; | ||
}; | ||
|
||
export type Fallback = { | ||
state: FileItemState; | ||
isInverted: boolean; | ||
isExtended: boolean; | ||
thumbnail: FileItemThumbnail; | ||
}; | ||
|
||
export const fallback: Fallback = { | ||
state: 'uploading', | ||
isInverted: false, | ||
isExtended: false, | ||
thumbnail: 'none', | ||
}; |
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,124 @@ | ||
import { action } from '@storybook/addon-actions'; | ||
import type { Meta, StoryObj } from '@storybook/react'; | ||
|
||
import { FileItem } from './FileItem'; | ||
import { mockTextFile, mockImageFile } from './mocks'; | ||
|
||
import { FileItemDocs } from '@/docs-components/FileItemDocs'; | ||
import { TetDocs } from '@/docs-components/TetDocs'; | ||
|
||
const meta = { | ||
title: 'FileItem', | ||
component: FileItem, | ||
tags: ['autodocs'], | ||
argTypes: {}, | ||
args: { | ||
file: mockTextFile(), | ||
state: 'uploaded', | ||
isInverted: false, | ||
isExtended: false, | ||
thumbnail: 'none', | ||
uploadedPercentage: 25, | ||
timeLeftText: '7 seconds left', | ||
alertText: 'Short alert text', | ||
onReplaceClick: action('onReplaceClick'), | ||
onRetryClick: action('onRetryClick'), | ||
onCloseClick: action('onCloseClick'), | ||
}, | ||
parameters: { | ||
docs: { | ||
description: { | ||
component: | ||
'Enable users to upload specific files, such as images, documents, or videos, to a particular location. The user can perform this action by dragging and dropping files into the designated area or browsing local storage.', | ||
}, | ||
page: () => ( | ||
<TetDocs docs="https://docs.tetrisly.com/components/in-progress/fileuploader"> | ||
<FileItemDocs /> | ||
</TetDocs> | ||
), | ||
}, | ||
}, | ||
} satisfies Meta<typeof FileItem>; | ||
|
||
export default meta; | ||
type Story = StoryObj<typeof meta>; | ||
|
||
export const Default: Story = { | ||
args: {}, | ||
}; | ||
|
||
export const Uploading: Story = { | ||
args: { | ||
state: 'uploading', | ||
}, | ||
}; | ||
|
||
export const Uploaded: Story = { | ||
args: {}, | ||
}; | ||
|
||
export const Replaceable: Story = { | ||
args: { | ||
state: 'replaceable', | ||
}, | ||
}; | ||
|
||
export const Alert: Story = { | ||
args: { | ||
state: 'alert', | ||
}, | ||
}; | ||
|
||
export const ExtendedUploading: Story = { | ||
args: { | ||
state: 'uploading', | ||
isExtended: true, | ||
}, | ||
}; | ||
|
||
export const ExtendedUploaded: Story = { | ||
args: { | ||
isExtended: true, | ||
}, | ||
}; | ||
|
||
export const ExtendedReplaceable: Story = { | ||
args: { | ||
state: 'replaceable', | ||
isExtended: true, | ||
}, | ||
}; | ||
|
||
export const ExtendedAlert: Story = { | ||
args: { | ||
state: 'alert', | ||
isExtended: true, | ||
}, | ||
}; | ||
|
||
export const ExtendedUploadingFile: Story = { | ||
args: { | ||
state: 'uploading', | ||
isExtended: true, | ||
thumbnail: 'file', | ||
}, | ||
}; | ||
|
||
export const ExtendedAlertImage: Story = { | ||
args: { | ||
file: mockImageFile(), | ||
state: 'alert', | ||
isExtended: true, | ||
thumbnail: 'photo', | ||
}, | ||
}; | ||
|
||
export const ExtendedInvertedAlertImage: Story = { | ||
args: { | ||
file: mockImageFile(), | ||
state: 'alert', | ||
isExtended: true, | ||
isInverted: true, | ||
thumbnail: 'photo', | ||
}, | ||
}; |
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,52 @@ | ||
import { compressedVariantStyles, extendedVariantStyles } from './components'; | ||
|
||
import type { BaseProps } from '@/types/BaseProps'; | ||
|
||
export type FileItemConfig = BaseProps & { | ||
state?: { | ||
uploading?: BaseProps; | ||
uploaded?: BaseProps; | ||
replaceable?: BaseProps; | ||
alert?: BaseProps; | ||
}; | ||
inverted?: BaseProps; | ||
invertedAlert?: BaseProps; | ||
compressed?: BaseProps; | ||
extended?: BaseProps; | ||
}; | ||
|
||
export const defaultConfig = { | ||
display: 'flex', | ||
flexDirection: 'column', | ||
gap: '$space-component-gap-small', | ||
borderRadius: '$border-radius-large', | ||
state: { | ||
uploading: { | ||
backgroundColor: '$color-interaction-neutral-subtle-normal', | ||
}, | ||
uploaded: { | ||
backgroundColor: '$color-interaction-default-subtle-normal', | ||
}, | ||
replaceable: { | ||
backgroundColor: '$color-interaction-default-subtle-normal', | ||
}, | ||
alert: { | ||
backgroundColor: '$color-interaction-alert-subtle-normal', | ||
}, | ||
}, | ||
inverted: { | ||
backgroundColor: '$color-interaction-background-formField', | ||
borderWidth: '$border-width-small', | ||
borderStyle: '$border-style-solid', | ||
borderColor: '$color-interaction-border-neutral-normal', | ||
}, | ||
invertedAlert: { | ||
borderColor: '$color-interaction-border-alert', | ||
}, | ||
compressed: compressedVariantStyles.defaultConfig, | ||
extended: extendedVariantStyles.defaultConfig, | ||
} as const satisfies FileItemConfig; | ||
|
||
export const fileItemStyles = { | ||
defaultConfig, | ||
}; |
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,151 @@ | ||
import { vi } from 'vitest'; | ||
|
||
import { FileItem } from './FileItem'; | ||
import { mockImageFile, mockTextFile } from './mocks'; | ||
import { render, screen, fireEvent } from '../../tests/render'; | ||
|
||
describe('FileItem', () => { | ||
it('should render empty file item', () => { | ||
render(<FileItem file={mockTextFile()} />); | ||
const fileItem = screen.getByTestId('file-item'); | ||
expect(fileItem).toBeInTheDocument(); | ||
|
||
const fileName = screen.getByTestId('file-name'); | ||
expect(fileName).toBeInTheDocument(); | ||
|
||
const fileSize = screen.getByTestId('file-size'); | ||
expect(fileSize).toBeInTheDocument(); | ||
|
||
const closeIcon = screen.getByTestId('close-icon'); | ||
expect(closeIcon).toBeInTheDocument(); | ||
}); | ||
|
||
it('should call onReplaceClick after click to Replace button', () => { | ||
const onReplaceClick = vi.fn(); | ||
|
||
render( | ||
<FileItem | ||
file={mockTextFile()} | ||
state="replaceable" | ||
onReplaceClick={onReplaceClick} | ||
/>, | ||
); | ||
|
||
const replaceableButton = screen.getByTestId('replaceable-button'); | ||
expect(replaceableButton).toBeInTheDocument(); | ||
|
||
fireEvent.click(replaceableButton); | ||
expect(onReplaceClick).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should call onRetryClick after click to Retry button', () => { | ||
const onRetryClick = vi.fn(); | ||
|
||
render( | ||
<FileItem | ||
file={mockTextFile()} | ||
state="alert" | ||
onRetryClick={onRetryClick} | ||
/>, | ||
); | ||
|
||
const retryButton = screen.getByTestId('retry-button'); | ||
expect(retryButton).toBeInTheDocument(); | ||
|
||
fireEvent.click(retryButton); | ||
expect(onRetryClick).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should call onCloseClick after click to close button', () => { | ||
const onCloseClick = vi.fn(); | ||
|
||
render( | ||
<FileItem | ||
file={mockTextFile()} | ||
state="uploading" | ||
onCloseClick={onCloseClick} | ||
/>, | ||
); | ||
|
||
const closeButton = screen.getByTestId('close-icon'); | ||
expect(closeButton).toBeInTheDocument(); | ||
|
||
fireEvent.click(closeButton); | ||
expect(onCloseClick).toHaveBeenCalled(); | ||
}); | ||
|
||
it('should render progress bar in uploading state', () => { | ||
render(<FileItem file={mockTextFile()} state="uploading" />); | ||
const progressBar = screen.getByTestId('progress-bar'); | ||
expect(progressBar).toBeInTheDocument(); | ||
}); | ||
|
||
it('should show uploaded percentage in uploading state', () => { | ||
render( | ||
<FileItem | ||
file={mockTextFile()} | ||
state="uploading" | ||
isExtended | ||
uploadedPercentage={76.25} | ||
/>, | ||
); | ||
const uploadedPercentage = screen.getByTestId('uploaded-percentage'); | ||
expect(uploadedPercentage).toBeInTheDocument(); | ||
expect(uploadedPercentage.innerHTML).toEqual('76.25%'); | ||
}); | ||
|
||
it('should show alert text in compressed alert state', () => { | ||
render( | ||
<FileItem | ||
file={mockTextFile()} | ||
state="alert" | ||
alertText="Short alert text" | ||
/>, | ||
); | ||
const alertText = screen.getByTestId('alert-text'); | ||
expect(alertText).toBeInTheDocument(); | ||
expect(alertText.innerHTML).toEqual('Short alert text'); | ||
}); | ||
|
||
it('should show alert text in extended alert state', () => { | ||
render( | ||
<FileItem | ||
file={mockTextFile()} | ||
isExtended | ||
state="alert" | ||
alertText="Short alert text" | ||
/>, | ||
); | ||
const alertInfo = screen.getByTestId('alert-info'); | ||
expect(alertInfo).toBeInTheDocument(); | ||
expect(alertInfo.innerHTML).toContain('Short alert text'); | ||
}); | ||
|
||
it('should show thumbnail file icon', () => { | ||
render( | ||
<FileItem | ||
file={mockTextFile()} | ||
isExtended | ||
state="uploaded" | ||
thumbnail="file" | ||
/>, | ||
); | ||
const thumbnailFile = screen.getByTestId('thumbnail-file'); | ||
expect(thumbnailFile).toBeInTheDocument(); | ||
}); | ||
|
||
it('should show thumbnail photo image', () => { | ||
Object.defineProperty(window.URL, 'createObjectURL', { value: () => '' }); | ||
|
||
render( | ||
<FileItem | ||
file={mockImageFile()} | ||
isExtended | ||
state="uploaded" | ||
thumbnail="photo" | ||
/>, | ||
); | ||
const thumbnailPhoto = screen.getByTestId('thumbnail-photo'); | ||
expect(thumbnailPhoto).toBeInTheDocument(); | ||
}); | ||
}); |
Oops, something went wrong.