From 1ebae2bed4a18cee53c4640462479f1f4ba5e971 Mon Sep 17 00:00:00 2001 From: ilana barbosa Date: Tue, 12 Mar 2024 10:39:29 -0300 Subject: [PATCH 1/2] feat(multi-select): add suffix --- .../MultiSelect/MultiSelect.stories.tsx | 24 +++++++++++++++++++ .../MultiSelect/MultiSelect.test.tsx | 17 ++++++++++++- src/components/MultiSelect/MultiSelect.tsx | 3 ++- .../MultiSelect/MultiSelectFetchable.tsx | 6 +++-- .../MultiSelect/MultiSelectStatic.tsx | 7 ++++-- 5 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/components/MultiSelect/MultiSelect.stories.tsx b/src/components/MultiSelect/MultiSelect.stories.tsx index d3fe5074..48c7aea4 100644 --- a/src/components/MultiSelect/MultiSelect.stories.tsx +++ b/src/components/MultiSelect/MultiSelect.stories.tsx @@ -6,6 +6,8 @@ import { MultiSelect } from './MultiSelect' import { createPageExport } from '../../utils/storybook' +import { IoIosArrowDown } from 'react-icons/io' + const aiqProps = [ 'maxWidth', 'filters', @@ -160,3 +162,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 ( + + } + errorForm={value.length === 0} + {...args} + /> + + ) +} diff --git a/src/components/MultiSelect/MultiSelect.test.tsx b/src/components/MultiSelect/MultiSelect.test.tsx index 0eb6ceaf..39ba2586 100644 --- a/src/components/MultiSelect/MultiSelect.test.tsx +++ b/src/components/MultiSelect/MultiSelect.test.tsx @@ -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' @@ -149,4 +150,18 @@ describe('MultiSelect', () => { const BadgeItem = getByTestId('select-selected-item') expect(BadgeItem).toHaveStyle({ backgroundColor: greenColor }) }) + + it('should show suffix when prop is provided', () => { + const { container } = render( + } + /> + ) + + const suffix = container.querySelector('svg') + + expect(suffix).toBeInTheDocument() + }) }) diff --git a/src/components/MultiSelect/MultiSelect.tsx b/src/components/MultiSelect/MultiSelect.tsx index 865f5b4f..b81bf96a 100644 --- a/src/components/MultiSelect/MultiSelect.tsx +++ b/src/components/MultiSelect/MultiSelect.tsx @@ -1,4 +1,4 @@ -import React from 'react' +import React, { ReactNode } from 'react' import { MultiSelectFetchable } from './MultiSelectFetchable' import { MultiSelectStatic } from './MultiSelectStatic' @@ -22,6 +22,7 @@ export interface Props { value?: Item[] items: Item[] isLoading?: boolean + suffix?: ReactNode isFetchable?: boolean placeholder?: string loadingMessage?: string diff --git a/src/components/MultiSelect/MultiSelectFetchable.tsx b/src/components/MultiSelect/MultiSelectFetchable.tsx index 47dde7f5..ee399c53 100644 --- a/src/components/MultiSelect/MultiSelectFetchable.tsx +++ b/src/components/MultiSelect/MultiSelectFetchable.tsx @@ -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' @@ -33,6 +33,7 @@ export interface Props { value?: Item[] items: Item[] isLoading?: boolean + suffix?: ReactNode placeholder?: string loadingMessage?: string emptyMessage?: string @@ -149,6 +150,7 @@ export const MultiSelectFetchable: React.FC = ({ onChange, value = [], isLoading = false, + suffix, placeholder, loadingMessage = 'carregando...', emptyMessage = 'item não encontrado ou já adicionado', @@ -392,7 +394,7 @@ export const MultiSelectFetchable: React.FC = ({ autoComplete='disabled' /> - {isLoading && } + {isLoading ? : suffix} = ({ onChange, value = [], placeholder, + suffix, errorForm, errorMessage, emptyMessage = 'item não encontrado ou já adicionado', @@ -422,6 +423,8 @@ export const MultiSelectStatic: React.FC = ({ )} autoComplete='disabled' /> + + {suffix} Date: Wed, 13 Mar 2024 09:39:15 -0300 Subject: [PATCH 2/2] feat(multi-select): add selection limit option --- .../MultiSelect/MultiSelect.stories.tsx | 2 ++ .../MultiSelect/MultiSelect.test.tsx | 17 +++++++++++ src/components/MultiSelect/MultiSelect.tsx | 2 ++ .../MultiSelect/MultiSelectFetchable.tsx | 9 ++++++ .../MultiSelect/MultiSelectStatic.tsx | 29 ++++++++++++------- 5 files changed, 49 insertions(+), 10 deletions(-) diff --git a/src/components/MultiSelect/MultiSelect.stories.tsx b/src/components/MultiSelect/MultiSelect.stories.tsx index 48c7aea4..e76287a8 100644 --- a/src/components/MultiSelect/MultiSelect.stories.tsx +++ b/src/components/MultiSelect/MultiSelect.stories.tsx @@ -14,6 +14,7 @@ const aiqProps = [ 'onChange', 'value', 'items', + 'selectedItemsLimit', 'isLoading', 'isFetchable', 'placeholder', @@ -33,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' }, diff --git a/src/components/MultiSelect/MultiSelect.test.tsx b/src/components/MultiSelect/MultiSelect.test.tsx index 39ba2586..88925c56 100644 --- a/src/components/MultiSelect/MultiSelect.test.tsx +++ b/src/components/MultiSelect/MultiSelect.test.tsx @@ -164,4 +164,21 @@ describe('MultiSelect', () => { expect(suffix).toBeInTheDocument() }) + + it('should show limit message when the selected items limit is reached', () => { + const { container } = render( + } + selectedItemsLimit={2} + /> + ) + + const list = container.querySelectorAll('li') + const firstItemText = list[0].textContent + + expect(list.length).toBe(1) + expect(firstItemText).toContain('quantidade máxima atingida') + }) }) diff --git a/src/components/MultiSelect/MultiSelect.tsx b/src/components/MultiSelect/MultiSelect.tsx index b81bf96a..12742943 100644 --- a/src/components/MultiSelect/MultiSelect.tsx +++ b/src/components/MultiSelect/MultiSelect.tsx @@ -21,6 +21,8 @@ export interface Props { onChange?: any value?: Item[] items: Item[] + selectedItemsLimit?: number + limitMessage?: string isLoading?: boolean suffix?: ReactNode isFetchable?: boolean diff --git a/src/components/MultiSelect/MultiSelectFetchable.tsx b/src/components/MultiSelect/MultiSelectFetchable.tsx index ee399c53..3aaedeac 100644 --- a/src/components/MultiSelect/MultiSelectFetchable.tsx +++ b/src/components/MultiSelect/MultiSelectFetchable.tsx @@ -32,6 +32,8 @@ export interface Props { onChange?: any value?: Item[] items: Item[] + selectedItemsLimit?: number + limitMessage?: string isLoading?: boolean suffix?: ReactNode placeholder?: string @@ -145,6 +147,8 @@ const SelectedItem = styled(Text)` export const MultiSelectFetchable: React.FC = ({ items, + selectedItemsLimit, + limitMessage = 'quantidade máxima atingida', maxWidth, filters = [], onChange, @@ -291,6 +295,8 @@ export const MultiSelectFetchable: React.FC = ({ } } + const hasReachedLimit = selectedItemsLimit === selectedItems?.length + return ( = ({ !isDependent && !isLoading && !disabled && + !hasReachedLimit && getFilteredItems().map((item, index) => (
  • = ({ !isLoading && !isDependent && getFilteredItems().length === 0 &&
  • {emptyMessage}
  • } + + {hasReachedLimit &&
  • {limitMessage}
  • }
    diff --git a/src/components/MultiSelect/MultiSelectStatic.tsx b/src/components/MultiSelect/MultiSelectStatic.tsx index 8360a6b5..680c5737 100644 --- a/src/components/MultiSelect/MultiSelectStatic.tsx +++ b/src/components/MultiSelect/MultiSelectStatic.tsx @@ -31,6 +31,8 @@ export interface Props { onChange?: any value?: Item[] items: Item[] + selectedItemsLimit?: number + limitMessage?: string suffix?: ReactNode isFetchable?: boolean placeholder?: string @@ -169,6 +171,8 @@ const CustomText = styled(Text)` export const MultiSelectStatic: React.FC = ({ items, + selectedItemsLimit, + limitMessage = 'quantidade máxima atingida', maxWidth, filters = [], onChange, @@ -316,6 +320,17 @@ export const MultiSelectStatic: React.FC = ({ } } + 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 ( = ({ {isOpen && !isDependent && !disabled && + !hasReachedLimit && getFilteredItems().map((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) - }} + onClick={e => handleSelect({ e, item, index })} > {item.name}
  • @@ -518,6 +525,8 @@ export const MultiSelectStatic: React.FC = ({ {isOpen && !isDependent && getFilteredItems().length === 0 && (
  • {emptyMessage}
  • )} + + {hasReachedLimit &&
  • {limitMessage}
  • }