From 6be3a1223f538f826211a5853c9d7b2da8f961f6 Mon Sep 17 00:00:00 2001 From: Alejandro Celaya Date: Fri, 25 Dec 2020 10:29:25 +0100 Subject: [PATCH] Created common Dropdown component for style consistency --- src/domains/DomainSelector.scss | 21 +-------- src/domains/DomainSelector.tsx | 58 ++++++++---------------- src/utils/Dropdown.scss | 19 ++++++++ src/utils/Dropdown.tsx | 21 +++++++++ src/utils/dates/DateRangeSelector.scss | 19 -------- src/utils/dates/DateRangeSelector.tsx | 61 ++++++++++++-------------- test/domains/DomainSelector.test.tsx | 9 ++-- 7 files changed, 92 insertions(+), 116 deletions(-) create mode 100644 src/utils/Dropdown.scss create mode 100644 src/utils/Dropdown.tsx delete mode 100644 src/utils/dates/DateRangeSelector.scss diff --git a/src/domains/DomainSelector.scss b/src/domains/DomainSelector.scss index c9ab0ba0..89e02433 100644 --- a/src/domains/DomainSelector.scss +++ b/src/domains/DomainSelector.scss @@ -1,31 +1,12 @@ @import '../utils/mixins/vertical-align'; -.domains-dropdown__toggle-btn.domains-dropdown__toggle-btn, -.domains-dropdown__toggle-btn.domains-dropdown__toggle-btn:hover, -.domains-dropdown__toggle-btn.domains-dropdown__toggle-btn:active { - text-align: left; - color: #6c757d; - border-color: #ced4da; - background-color: white; -} - .domains-dropdown__toggle-btn--active.domains-dropdown__toggle-btn--active, .domains-dropdown__toggle-btn--active.domains-dropdown__toggle-btn--active:hover, .domains-dropdown__toggle-btn--active.domains-dropdown__toggle-btn--active:active { - color: #495057; + color: #495057 !important; } .domains-dropdown__back-btn.domains-dropdown__back-btn, .domains-dropdown__back-btn.domains-dropdown__back-btn:hover { border-color: #ced4da; } - -.domains-dropdown__toggle-btn.domains-dropdown__toggle-btn::after { - right: .75rem; - - @include vertical-align(); -} - -.domains-dropdown__menu { - width: 100%; -} diff --git a/src/domains/DomainSelector.tsx b/src/domains/DomainSelector.tsx index 510b39f9..f034731b 100644 --- a/src/domains/DomainSelector.tsx +++ b/src/domains/DomainSelector.tsx @@ -1,20 +1,10 @@ import { useEffect } from 'react'; -import { - Button, - Dropdown, - DropdownItem, - DropdownMenu, - DropdownToggle, - Input, - InputGroup, - InputGroupAddon, - UncontrolledTooltip, -} from 'reactstrap'; +import { Button, DropdownItem, Input, InputGroup, InputGroupAddon, UncontrolledTooltip } from 'reactstrap'; import { InputProps } from 'reactstrap/lib/Input'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faUndo } from '@fortawesome/free-solid-svg-icons'; import { isEmpty, pipe } from 'ramda'; -import classNames from 'classnames'; +import { Dropdown } from '../utils/Dropdown'; import { useToggle } from '../utils/helpers/hooks'; import { DomainsList } from './reducers/domainsList'; import './DomainSelector.scss'; @@ -31,7 +21,6 @@ interface DomainSelectorConnectProps extends DomainSelectorProps { export const DomainSelector = ({ listDomains, value, domainsList, onChange }: DomainSelectorConnectProps) => { const [ inputDisplayed,, showInput, hideInput ] = useToggle(); - const [ isDropdownOpen, toggleDropdown ] = useToggle(); const { domains } = domainsList; const valueIsEmpty = isEmpty(value); const unselectDomain = () => onChange(''); @@ -63,33 +52,24 @@ export const DomainSelector = ({ listDomains, value, domainsList, onChange }: Do ) : ( - - - {valueIsEmpty && <>Domain} - {!valueIsEmpty && <>Domain: {value}} - - - {domains.map(({ domain, isDefault }) => ( - onChange(domain)} - > - {domain} - {isDefault && default} - - ))} - - - New domain + + {domains.map(({ domain, isDefault }) => ( + onChange(domain)} + > + {domain} + {isDefault && default} - + ))} + + + New domain + ); }; diff --git a/src/utils/Dropdown.scss b/src/utils/Dropdown.scss new file mode 100644 index 00000000..f7a91eed --- /dev/null +++ b/src/utils/Dropdown.scss @@ -0,0 +1,19 @@ +@import '../utils/mixins/vertical-align'; + +.dropdown__btn.dropdown__btn, +.dropdown__btn.dropdown__btn:not(:disabled):not(.disabled).active, +.dropdown__btn.dropdown__btn:not(:disabled):not(.disabled):active, +.dropdown__btn.dropdown__btn:not(:disabled):not(.disabled):focus, +.dropdown__btn.dropdown__btn:not(:disabled):not(.disabled):hover, +.show > .dropdown__btn.dropdown__btn.dropdown-toggle { + color: #6c757d; + background-color: white; + text-align: left; + border-color: rgba(0, 0, 0, .125); +} + +.dropdown__btn.dropdown__btn:after { + @include vertical-align(); + + right: .75rem; +} diff --git a/src/utils/Dropdown.tsx b/src/utils/Dropdown.tsx new file mode 100644 index 00000000..d6931310 --- /dev/null +++ b/src/utils/Dropdown.tsx @@ -0,0 +1,21 @@ +import { FC } from 'react'; +import { Dropdown as BsDropdown, DropdownMenu, DropdownToggle } from 'reactstrap'; +import { useToggle } from './helpers/hooks'; +import './Dropdown.scss'; + +interface DropdownProps { + text: string; + disabled?: boolean; + className?: string; +} + +export const Dropdown: FC = ({ text, disabled = false, className, children }) => { + const [ isOpen, toggle ] = useToggle(); + + return ( + + {text} + {children} + + ); +}; diff --git a/src/utils/dates/DateRangeSelector.scss b/src/utils/dates/DateRangeSelector.scss deleted file mode 100644 index 114c2b12..00000000 --- a/src/utils/dates/DateRangeSelector.scss +++ /dev/null @@ -1,19 +0,0 @@ -@import '../../utils/mixins/vertical-align'; - -.date-range-selector__btn.date-range-selector__btn, -.date-range-selector__btn.date-range-selector__btn:not(:disabled):not(.disabled).active, -.date-range-selector__btn.date-range-selector__btn:not(:disabled):not(.disabled):active, -.date-range-selector__btn.date-range-selector__btn:not(:disabled):not(.disabled):focus, -.date-range-selector__btn.date-range-selector__btn:not(:disabled):not(.disabled):hover, -.show > .date-range-selector__btn.date-range-selector__btn.dropdown-toggle { - color: #6c757d; - background-color: white; - text-align: left; - border-color: rgba(0, 0, 0, .125); -} - -.date-range-selector__btn.date-range-selector__btn:after { - @include vertical-align(); - - right: .75rem; -} diff --git a/src/utils/dates/DateRangeSelector.tsx b/src/utils/dates/DateRangeSelector.tsx index 7fbdc7bf..9d8e0d93 100644 --- a/src/utils/dates/DateRangeSelector.tsx +++ b/src/utils/dates/DateRangeSelector.tsx @@ -1,6 +1,6 @@ import { useState } from 'react'; -import { Dropdown, DropdownItem, DropdownMenu, DropdownToggle } from 'reactstrap'; -import { useToggle } from '../helpers/hooks'; +import { DropdownItem } from 'reactstrap'; +import { Dropdown } from '../Dropdown'; import { DateInterval, DateRange, @@ -10,7 +10,6 @@ import { rangeIsInterval, } from './types'; import DateRangeRow from './DateRangeRow'; -import './DateRangeSelector.scss'; export interface DateRangeSelectorProps { initialDateRange?: DateInterval | DateRange; @@ -20,9 +19,8 @@ export interface DateRangeSelectorProps { } export const DateRangeSelector = ( - { onDatesChange, initialDateRange, defaultText, disabled = false }: DateRangeSelectorProps, + { onDatesChange, initialDateRange, defaultText, disabled }: DateRangeSelectorProps, ) => { - const [ isOpen, toggle ] = useToggle(); const [ activeInterval, setActiveInterval ] = useState( rangeIsInterval(initialDateRange) ? initialDateRange : undefined, ); @@ -41,35 +39,30 @@ export const DateRangeSelector = ( }; return ( - - - {rangeOrIntervalToString(activeInterval ?? activeDateRange) ?? defaultText} - - - - {defaultText} - - - {([ 'today', 'yesterday', 'last7Days', 'last30Days', 'last90Days', 'last180days', 'last365Days' ] as DateInterval[]).map( - (interval) => ( - - {rangeOrIntervalToString(interval)} - - ), - )} - - Custom: - - updateDateRange({ ...activeDateRange, startDate })} - onEndDateChange={(endDate) => updateDateRange({ ...activeDateRange, endDate })} - /> - - + + + {defaultText} + + + {([ 'today', 'yesterday', 'last7Days', 'last30Days', 'last90Days', 'last180days', 'last365Days' ] as DateInterval[]).map( + (interval) => ( + + {rangeOrIntervalToString(interval)} + + ), + )} + + Custom: + + updateDateRange({ ...activeDateRange, startDate })} + onEndDateChange={(endDate) => updateDateRange({ ...activeDateRange, endDate })} + /> + ); }; diff --git a/test/domains/DomainSelector.test.tsx b/test/domains/DomainSelector.test.tsx index 0c1ab22c..0e080a01 100644 --- a/test/domains/DomainSelector.test.tsx +++ b/test/domains/DomainSelector.test.tsx @@ -1,9 +1,10 @@ import { shallow, ShallowWrapper } from 'enzyme'; import { Mock } from 'ts-mockery'; -import { DropdownItem, DropdownMenu, InputGroup } from 'reactstrap'; +import { DropdownItem, InputGroup } from 'reactstrap'; import { DomainSelector } from '../../src/domains/DomainSelector'; import { DomainsList } from '../../src/domains/reducers/domainsList'; import { ShlinkDomain } from '../../src/api/types'; +import { Dropdown } from '../../src/utils/Dropdown'; describe('', () => { let wrapper: ShallowWrapper; @@ -23,7 +24,7 @@ describe('', () => { it('shows dropdown by default', () => { const input = wrapper.find(InputGroup); - const dropdown = wrapper.find(DropdownMenu); + const dropdown = wrapper.find(Dropdown); expect(input).toHaveLength(0); expect(dropdown).toHaveLength(1); @@ -33,10 +34,10 @@ describe('', () => { it('allows to toggle between dropdown and input', () => { wrapper.find(DropdownItem).last().simulate('click'); expect(wrapper.find(InputGroup)).toHaveLength(1); - expect(wrapper.find(DropdownMenu)).toHaveLength(0); + expect(wrapper.find(Dropdown)).toHaveLength(0); wrapper.find('.domains-dropdown__back-btn').simulate('click'); expect(wrapper.find(InputGroup)).toHaveLength(0); - expect(wrapper.find(DropdownMenu)).toHaveLength(1); + expect(wrapper.find(Dropdown)).toHaveLength(1); }); });