diff --git a/src/settings/Settings.tsx b/src/settings/Settings.tsx index 294115a0..fc8ea340 100644 --- a/src/settings/Settings.tsx +++ b/src/settings/Settings.tsx @@ -20,8 +20,8 @@ const Settings = (RealTimeUpdates: FC, ShortUrlCreation: FC, UserInterface: FC, , ], // eslint-disable-line react/jsx-key - [ , ], // eslint-disable-line react/jsx-key + [ , ], // eslint-disable-line react/jsx-key + [ , ], // eslint-disable-line react/jsx-key ]} /> diff --git a/src/settings/ShortUrlCreation.tsx b/src/settings/ShortUrlCreation.tsx index b91ed500..f180a3ed 100644 --- a/src/settings/ShortUrlCreation.tsx +++ b/src/settings/ShortUrlCreation.tsx @@ -1,29 +1,62 @@ -import { FC } from 'react'; -import { FormGroup } from 'reactstrap'; +import { FC, ReactNode } from 'react'; +import { DropdownItem, FormGroup } from 'reactstrap'; import { SimpleCard } from '../utils/SimpleCard'; import ToggleSwitch from '../utils/ToggleSwitch'; -import { Settings, ShortUrlCreationSettings } from './reducers/settings'; +import { DropdownBtn } from '../utils/DropdownBtn'; +import { Settings, ShortUrlCreationSettings, TagFilteringMode } from './reducers/settings'; interface ShortUrlCreationProps { settings: Settings; setShortUrlCreationSettings: (settings: ShortUrlCreationSettings) => void; } -export const ShortUrlCreation: FC = ( - { settings: { shortUrlCreation }, setShortUrlCreationSettings }, -) => ( - - - setShortUrlCreationSettings({ validateUrls })} - > - By default, request validation on long URLs when creating new short URLs. +const tagFilteringModeText = (tagFilteringMode: TagFilteringMode | undefined): string => + tagFilteringMode === 'includes' ? 'Suggest tags including input' : 'Suggest tags starting with input'; +const tagFilteringModeHint = (tagFilteringMode: TagFilteringMode | undefined): ReactNode => + tagFilteringMode === 'includes' + ? <>The list of suggested tags will contain existing ones including provided input. + : <>The list of suggested tags will contain existing ones starting with provided input.; + +export const ShortUrlCreation: FC = ({ settings, setShortUrlCreationSettings }) => { + const shortUrlCreation: ShortUrlCreationSettings = settings.shortUrlCreation ?? { validateUrls: false }; + const changeTagsFilteringMode = (tagFilteringMode: TagFilteringMode) => () => setShortUrlCreationSettings( + { ...shortUrlCreation ?? { validateUrls: false }, tagFilteringMode }, + ); + + return ( + + + setShortUrlCreationSettings({ ...shortUrlCreation, validateUrls })} + > + By default, request validation on long URLs when creating new short URLs. + + The initial state of the Validate URL checkbox will + be {shortUrlCreation.validateUrls ? 'checked' : 'unchecked'}. + + + + + + + + {tagFilteringModeText('startsWith')} + + + {tagFilteringModeText('includes')} + + - The initial state of the Validate URL checkbox will - be {shortUrlCreation?.validateUrls ? 'checked' : 'unchecked'}. + {tagFilteringModeHint(shortUrlCreation.tagFilteringMode)} - - - -); + + + ); +} diff --git a/src/settings/reducers/settings.ts b/src/settings/reducers/settings.ts index df405e2a..f052893c 100644 --- a/src/settings/reducers/settings.ts +++ b/src/settings/reducers/settings.ts @@ -17,12 +17,11 @@ interface RealTimeUpdatesSettings { interval?: number; } -type TagFilteringMode = 'startsWith' | 'includes'; +export type TagFilteringMode = 'startsWith' | 'includes'; export interface ShortUrlCreationSettings { validateUrls: boolean; - tagFilteringMode?: TagFilteringMode; - maxTagSuggestions?: number; + tagFilteringMode?: TagFilteringMode } export interface UiSettings { diff --git a/src/tags/helpers/TagsSelector.tsx b/src/tags/helpers/TagsSelector.tsx index 83e62b15..8b585fe2 100644 --- a/src/tags/helpers/TagsSelector.tsx +++ b/src/tags/helpers/TagsSelector.tsx @@ -28,7 +28,6 @@ const TagsSelector = (colorGenerator: ColorGenerator) => ( }, []); const searchMode = settings.shortUrlCreation?.tagFilteringMode ?? 'startsWith'; - const maxSuggestions = settings.shortUrlCreation?.maxTagSuggestions; const ReactTagsTag = ({ tag, onDelete }: TagComponentProps) => ; const ReactTagsSuggestion = ({ item }: SuggestionComponentProps) => ( @@ -48,7 +47,6 @@ const TagsSelector = (colorGenerator: ColorGenerator) => ( addOnBlur placeholderText={placeholder ?? 'Add tags to the URL'} minQueryLength={1} - maxSuggestionsLength={maxSuggestions} delimiters={[ 'Enter', 'Tab', ',' ]} suggestionsTransform={ searchMode === 'includes' diff --git a/test/settings/ShortUrlCreation.test.tsx b/test/settings/ShortUrlCreation.test.tsx index 1cb92d9a..aee7df18 100644 --- a/test/settings/ShortUrlCreation.test.tsx +++ b/test/settings/ShortUrlCreation.test.tsx @@ -3,6 +3,8 @@ import { Mock } from 'ts-mockery'; import { ShortUrlCreationSettings, Settings } from '../../src/settings/reducers/settings'; import { ShortUrlCreation } from '../../src/settings/ShortUrlCreation'; import ToggleSwitch from '../../src/utils/ToggleSwitch'; +import { DropdownBtn } from '../../src/utils/DropdownBtn'; +import { DropdownItem } from 'reactstrap'; describe('', () => { let wrapper: ShallowWrapper; @@ -25,13 +27,41 @@ describe('', () => { [{ validateUrls: true }, true ], [{ validateUrls: false }, false ], [ undefined, false ], - ])('switch is toggled if option is true', (shortUrlCreation, expectedChecked) => { + ])('URL validation switch is toggled if option is true', (shortUrlCreation, expectedChecked) => { const wrapper = createWrapper(shortUrlCreation); const toggle = wrapper.find(ToggleSwitch); expect(toggle.prop('checked')).toEqual(expectedChecked); }); + it.each([ + [{ validateUrls: true }, 'checkbox will be checked' ], + [{ validateUrls: false }, 'checkbox will be unchecked' ], + [ undefined, 'checkbox will be unchecked' ], + ])('shows expected helper text for URL validation', (shortUrlCreation, expectedText) => { + const wrapper = createWrapper(shortUrlCreation); + const text = wrapper.find('.form-text').first(); + + expect(text.text()).toContain(expectedText); + }); + + it.each([ + [ { tagFilteringMode: 'includes' } as ShortUrlCreationSettings, 'Suggest tags including input', 'including' ], + [ + { tagFilteringMode: 'startsWith' } as ShortUrlCreationSettings, + 'Suggest tags starting with input', + 'starting with', + ], + [ undefined, 'Suggest tags starting with input', 'starting with' ], + ])('shows expected texts for tags suggestions', (shortUrlCreation, expectedText, expectedHint) => { + const wrapper = createWrapper(shortUrlCreation); + const hintText = wrapper.find('.form-text').last(); + const dropdown = wrapper.find(DropdownBtn); + + expect(dropdown.prop('text')).toEqual(expectedText); + expect(hintText.text()).toContain(expectedHint); + }); + it.each([[ true ], [ false ]])('invokes setShortUrlCreationSettings when toggle value changes', (validateUrls) => { const wrapper = createWrapper(); const toggle = wrapper.find(ToggleSwitch); @@ -41,14 +71,21 @@ describe('', () => { expect(setShortUrlCreationSettings).toHaveBeenCalledWith({ validateUrls }); }); - it.each([ - [{ validateUrls: true }, 'checkbox will be checked' ], - [{ validateUrls: false }, 'checkbox will be unchecked' ], - [ undefined, 'checkbox will be unchecked' ], - ])('shows expected helper text', (shortUrlCreation, expectedText) => { - const wrapper = createWrapper(shortUrlCreation); - const text = wrapper.find('.form-text'); + it('invokes setShortUrlCreationSettings when dropdown value changes', () => { + const wrapper = createWrapper(); + const firstDropdownItem = wrapper.find(DropdownItem).first(); + const secondDropdownItem = wrapper.find(DropdownItem).last(); - expect(text.text()).toContain(expectedText); + expect(setShortUrlCreationSettings).not.toHaveBeenCalled(); + + firstDropdownItem.simulate('click'); + expect(setShortUrlCreationSettings).toHaveBeenCalledWith(expect.objectContaining( + { tagFilteringMode: 'startsWith' }, + )); + + secondDropdownItem.simulate('click'); + expect(setShortUrlCreationSettings).toHaveBeenCalledWith(expect.objectContaining( + { tagFilteringMode: 'includes' }, + )); }); });