Skip to content

Commit

Permalink
feat(multi-select): add suffix and selection limit option (#482)
Browse files Browse the repository at this point in the history
* feat(multi-select): add suffix

* feat(multi-select): add selection limit option
  • Loading branch information
MrsBolinhu authored Mar 13, 2024
1 parent 9b0cb7a commit 71a3ec9
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 16 deletions.
26 changes: 26 additions & 0 deletions src/components/MultiSelect/MultiSelect.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import { MultiSelect } from './MultiSelect'

import { createPageExport } from '../../utils/storybook'

import { IoIosArrowDown } from 'react-icons/io'

const aiqProps = [
'maxWidth',
'filters',
'onChange',
'value',
'items',
'selectedItemsLimit',
'isLoading',
'isFetchable',
'placeholder',
Expand All @@ -31,6 +34,7 @@ export default createPageExport(MultiSelect, 'MultiSelect', aiqProps, {
filters: { control: 'object' },
value: { control: 'object' },
items: { control: 'object' },
selectedItemsLimit: { control: 'number' },
isLoading: { control: 'boolean' },
isFetchable: { control: 'number' },
placeholder: { control: 'text' },
Expand Down Expand Up @@ -160,3 +164,25 @@ export const DisabledWithoutElements = (args): ReactElement => {
DisabledWithoutElements.args = {
disabled: true
}

export const WithSuffix = (args): ReactElement => {
const [value, setValue] = useState([items[0]])

function handleChangeMultiSelect({ selectedItems }) {
setValue(selectedItems)
}

return (
<Flex variant='fullCentralized'>
<MultiSelect
value={value}
onChange={handleChangeMultiSelect}
filters={filters}
items={items}
suffix={<IoIosArrowDown />}
errorForm={value.length === 0}
{...args}
/>
</Flex>
)
}
34 changes: 33 additions & 1 deletion src/components/MultiSelect/MultiSelect.test.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import React, { useState } from 'react'
import React from 'react'
import { fireEvent } from '@testing-library/react'

import { MultiSelect } from '../MultiSelect'
import { render } from '../utils/test/render'
import { IoIosArrowDown } from 'react-icons/io'

const greenColor = '#6EC531'

Expand Down Expand Up @@ -149,4 +150,35 @@ describe('MultiSelect', () => {
const BadgeItem = getByTestId('select-selected-item')
expect(BadgeItem).toHaveStyle({ backgroundColor: greenColor })
})

it('should show suffix when prop is provided', () => {
const { container } = render(
<MultiSelect
items={items}
value={[items[0]]}
suffix={<IoIosArrowDown />}
/>
)

const suffix = container.querySelector('svg')

expect(suffix).toBeInTheDocument()
})

it('should show limit message when the selected items limit is reached', () => {
const { container } = render(
<MultiSelect
items={items}
value={[items[0], items[1]]}
suffix={<IoIosArrowDown />}
selectedItemsLimit={2}
/>
)

const list = container.querySelectorAll('li')
const firstItemText = list[0].textContent

expect(list.length).toBe(1)
expect(firstItemText).toContain('quantidade máxima atingida')
})
})
5 changes: 4 additions & 1 deletion src/components/MultiSelect/MultiSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React from 'react'
import React, { ReactNode } from 'react'

import { MultiSelectFetchable } from './MultiSelectFetchable'
import { MultiSelectStatic } from './MultiSelectStatic'
Expand All @@ -21,7 +21,10 @@ export interface Props {
onChange?: any
value?: Item[]
items: Item[]
selectedItemsLimit?: number
limitMessage?: string
isLoading?: boolean
suffix?: ReactNode
isFetchable?: boolean
placeholder?: string
loadingMessage?: string
Expand Down
15 changes: 13 additions & 2 deletions src/components/MultiSelect/MultiSelectFetchable.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useEffect, useRef, useState } from 'react'
import React, { ReactNode, useEffect, useRef, useState } from 'react'

import styled from 'styled-components'
import { MdClose } from 'react-icons/md'
Expand Down Expand Up @@ -32,7 +32,10 @@ export interface Props {
onChange?: any
value?: Item[]
items: Item[]
selectedItemsLimit?: number
limitMessage?: string
isLoading?: boolean
suffix?: ReactNode
placeholder?: string
loadingMessage?: string
emptyMessage?: string
Expand Down Expand Up @@ -144,11 +147,14 @@ const SelectedItem = styled(Text)`

export const MultiSelectFetchable: React.FC<Props> = ({
items,
selectedItemsLimit,
limitMessage = 'quantidade máxima atingida',
maxWidth,
filters = [],
onChange,
value = [],
isLoading = false,
suffix,
placeholder,
loadingMessage = 'carregando...',
emptyMessage = 'item não encontrado ou já adicionado',
Expand Down Expand Up @@ -289,6 +295,8 @@ export const MultiSelectFetchable: React.FC<Props> = ({
}
}

const hasReachedLimit = selectedItemsLimit === selectedItems?.length

return (
<Flex flexDirection='column' flex={1}>
<MultiSelectStyled
Expand Down Expand Up @@ -392,7 +400,7 @@ export const MultiSelectFetchable: React.FC<Props> = ({
autoComplete='disabled'
/>

{isLoading && <Loading size='small' />}
{isLoading ? <Loading size='small' /> : suffix}
</ContainerInput>

<Overflow
Expand Down Expand Up @@ -430,6 +438,7 @@ export const MultiSelectFetchable: React.FC<Props> = ({
!isDependent &&
!isLoading &&
!disabled &&
!hasReachedLimit &&
getFilteredItems().map((item, index) => (
<li
key={`${item}${index}`}
Expand All @@ -450,6 +459,8 @@ export const MultiSelectFetchable: React.FC<Props> = ({
!isLoading &&
!isDependent &&
getFilteredItems().length === 0 && <li>{emptyMessage}</li>}

{hasReachedLimit && <li>{limitMessage}</li>}
</ul>
</Itens>
</Overflow>
Expand Down
36 changes: 24 additions & 12 deletions src/components/MultiSelect/MultiSelectStatic.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import React, { useState, useRef, useEffect } from 'react'
import React, { useState, useRef, useEffect, ReactNode } from 'react'

import styled from 'styled-components'
import { MdClose } from 'react-icons/md'
Expand Down Expand Up @@ -31,7 +31,9 @@ export interface Props {
onChange?: any
value?: Item[]
items: Item[]
isLoading?: boolean
selectedItemsLimit?: number
limitMessage?: string
suffix?: ReactNode
isFetchable?: boolean
placeholder?: string
errorMessage?: string
Expand Down Expand Up @@ -169,11 +171,14 @@ const CustomText = styled(Text)`

export const MultiSelectStatic: React.FC<Props> = ({
items,
selectedItemsLimit,
limitMessage = 'quantidade máxima atingida',
maxWidth,
filters = [],
onChange,
value = [],
placeholder,
suffix,
errorForm,
errorMessage,
emptyMessage = 'item não encontrado ou já adicionado',
Expand Down Expand Up @@ -315,6 +320,17 @@ export const MultiSelectStatic: React.FC<Props> = ({
}
}

const handleSelect = ({ e, item, index }) => {
if (selectedItems.indexOf(item) > -1 && removable)
onChange({
selectedItems: selectedItems.filter(e => e.id !== item.id)
})
else getItemProps({ item, index }).onClick(e)
setItemLimit(undefined)
}

const hasReachedLimit = selectedItemsLimit === selectedItems?.length

return (
<Flex flexDirection='column' flex={1}>
<MultiSelectStyled
Expand Down Expand Up @@ -422,6 +438,8 @@ export const MultiSelectStatic: React.FC<Props> = ({
)}
autoComplete='disabled'
/>

{suffix}
</ContainerInput>

<Overflow
Expand Down Expand Up @@ -490,21 +508,13 @@ export const MultiSelectStatic: React.FC<Props> = ({
{isOpen &&
!isDependent &&
!disabled &&
!hasReachedLimit &&
getFilteredItems().map((item, index) => (
<li
key={`${item}${index}`}
data-testid='select-item'
{...getItemProps({ item, index })}
onClick={e => {
if (selectedItems.indexOf(item) > -1 && removable)
onChange({
selectedItems: selectedItems.filter(
e => e.id !== item.id
)
})
else getItemProps({ item, index }).onClick(e)
setItemLimit(undefined)
}}
onClick={e => handleSelect({ e, item, index })}
>
{item.name}
</li>
Expand All @@ -515,6 +525,8 @@ export const MultiSelectStatic: React.FC<Props> = ({
{isOpen && !isDependent && getFilteredItems().length === 0 && (
<li>{emptyMessage}</li>
)}

{hasReachedLimit && <li>{limitMessage}</li>}
</ul>
</Itens>
</Overflow>
Expand Down

0 comments on commit 71a3ec9

Please sign in to comment.