Skip to content
Snippets Groups Projects
Unverified Commit 7c80a200 authored by Matiss Janis Aboltins's avatar Matiss Janis Aboltins Committed by GitHub
Browse files

:recycle: (autocomplete) cleaning up state updates (#931)

parent e8a62f89
No related branches found
No related tags found
No related merge requests found
import React, { useState, useRef, useEffect } from 'react'; import React, { useState, useRef, useEffect, useMemo } from 'react';
import Downshift from 'downshift'; import Downshift from 'downshift';
import { css } from 'glamor'; import { css } from 'glamor';
import usePrevious from '../../hooks/usePrevious';
import Remove from '../../icons/v2/Remove'; import Remove from '../../icons/v2/Remove';
import { colors } from '../../style'; import { colors } from '../../style';
import { View, Input, Tooltip, Button } from '../common'; import { View, Input, Tooltip, Button } from '../common';
...@@ -35,79 +34,6 @@ function getItemId(item) { ...@@ -35,79 +34,6 @@ function getItemId(item) {
return item ? item.id : null; return item ? item.id : null;
} }
function getInitialState({
props: {
value,
suggestions,
embedded,
isOpen = false,
strict,
initialFilterSuggestions,
},
}) {
let selectedItem = findItem(strict, suggestions, value);
let filteredSuggestions = initialFilterSuggestions
? initialFilterSuggestions(suggestions, value)
: null;
return {
selectedItem,
value: selectedItem ? getItemName(selectedItem) : '',
originalItem: selectedItem,
filteredSuggestions,
highlightedIndex: null,
isOpen: embedded || isOpen,
};
}
function componentWillReceiveProps(bag, nextProps) {
let {
strict,
suggestions,
filterSuggestions = defaultFilterSuggestions,
initialFilterSuggestions,
value,
itemToString = defaultItemToString,
} = nextProps;
let { value: currValue } = bag.state;
let updates = null;
function updateValue() {
let selectedItem = findItem(strict, suggestions, value);
if (selectedItem) {
updates = updates || {};
updates.value = itemToString(selectedItem);
updates.selectedItem = selectedItem;
}
}
if (bag.props.value !== value) {
updateValue();
}
// TODO: Something is causing a rerender immediately after first
// render, and this condition is true, causing items to be filtered
// twice. This shouldn't effect functionality (I think), but look
// into this later
if (bag.props.suggestions !== suggestions) {
let filteredSuggestions = null;
if (bag.state.highlightedIndex != null) {
filteredSuggestions = filterSuggestions(suggestions, currValue);
} else {
filteredSuggestions = initialFilterSuggestions
? initialFilterSuggestions(suggestions, currValue)
: null;
}
updates = updates || {};
updateValue();
updates.filteredSuggestions = filteredSuggestions;
}
return updates;
}
export function defaultFilterSuggestion(suggestion, value) { export function defaultFilterSuggestion(suggestion, value) {
return getItemName(suggestion).toLowerCase().includes(value.toLowerCase()); return getItemName(suggestion).toLowerCase().includes(value.toLowerCase());
} }
...@@ -140,238 +66,7 @@ function fireUpdate(onUpdate, strict, suggestions, index, value) { ...@@ -140,238 +66,7 @@ function fireUpdate(onUpdate, strict, suggestions, index, value) {
} }
} }
onUpdate && onUpdate(selected); onUpdate && onUpdate(selected, value);
}
function onInputValueChange(
{
props: {
suggestions,
onUpdate,
highlightFirst,
strict,
filterSuggestions = defaultFilterSuggestions,
getHighlightedIndex,
},
},
value,
changes,
) {
// OMG this is the dumbest thing ever. I need to remove Downshift
// and build my own component. For some reason this is fired on blur
// with an empty value which clears out the input when the app blurs
if (!document.hasFocus()) {
return;
}
// Do nothing if it's simply updating the selected item
if (
changes.type ===
Downshift.stateChangeTypes.controlledPropUpdatedSelectedItem
) {
return;
}
// Otherwise, filter the items and always the first item if
// desired
const filteredSuggestions = filterSuggestions(suggestions, value);
if (value === '') {
// A blank value shouldn't highlight any item so that the field
// can be left blank if desired
if (changes.type !== Downshift.stateChangeTypes.clickItem) {
fireUpdate(onUpdate, strict, filteredSuggestions, null, null);
}
return {
value,
filteredSuggestions,
highlightedIndex: null,
};
} else {
let defaultGetHighlightedIndex = filteredSuggestions => {
return highlightFirst && filteredSuggestions.length ? 0 : null;
};
let highlightedIndex = (getHighlightedIndex || defaultGetHighlightedIndex)(
filteredSuggestions,
);
if (changes.type !== Downshift.stateChangeTypes.clickItem) {
fireUpdate(
onUpdate,
strict,
filteredSuggestions,
highlightedIndex,
value,
);
}
return {
value,
filteredSuggestions,
highlightedIndex,
};
}
}
function onStateChange({ props, state }, changes) {
if (
props.tableBehavior &&
changes.type === Downshift.stateChangeTypes.mouseUp
) {
return;
}
const newState = {};
if ('highlightedIndex' in changes) {
newState.highlightedIndex = changes.highlightedIndex;
}
if ('isOpen' in changes) {
newState.isOpen = props.embedded ? true : changes.isOpen;
}
if ('selectedItem' in changes) {
newState.selectedItem = changes.selectedItem;
}
// We only ever want to update the value if the user explicitly
// highlighted an item via the keyboard. It shouldn't change with
// mouseover; otherwise the user could accidentally hover over an
// item without realizing it and change the value.
if (
state.isOpen &&
(changes.type === Downshift.stateChangeTypes.keyDownArrowUp ||
changes.type === Downshift.stateChangeTypes.keyDownArrowDown)
) {
fireUpdate(
props.onUpdate,
props.strict,
state.filteredSuggestions || props.suggestions,
newState.highlightedIndex != null
? newState.highlightedIndex
: state.highlightedIndex,
state.value,
);
}
inst.lastChangeType = changes.type;
return newState;
}
function onSelect(
{ props: { onSelect, clearAfterSelect, suggestions } },
item,
) {
if (onSelect) {
// I AM NOT PROUD OF THIS OK??
// This WHOLE FILE is a mess anyway
// OK SIT DOWN AND I WILL EXPLAIN
// This component uses `componentWillReceiveProps` and in there
// it will re-filter suggestions if the suggestions change and
// a `highlightedIndex` exists. When we select something,
// we clear `highlightedIndex` so it should show all suggestions
// again. HOWEVER, in the case of a multi-autocomplete, it's
// changing the suggestions every time something is selected.
// In that case, cWRP is running *before* our state setting that
// cleared `highlightedIndex`. Forcing this to run later assures
// us that we will clear out local state before cWRP runs.
// YEAH THAT'S ALL OK I JUST WANT TO SHIP THIS
setTimeout(() => {
onSelect(getItemId(item));
}, 0);
}
return onSelectAfter(suggestions, clearAfterSelect);
}
function onSelectAfter(suggestions, clearAfterSelect) {
if (clearAfterSelect) {
return {
value: '',
selectedItem: null,
highlightedIndex: null,
filteredSuggestions: suggestions,
};
}
return { isOpen: false };
}
function onChange({ props: { inputProps } }, e) {
const { onChange } = inputProps || {};
onChange && onChange(e.target.value);
}
function onKeyDown(
{
props: {
suggestions,
clearAfterSelect,
initialFilterSuggestions,
embedded,
onUpdate,
onSelect,
inputProps,
shouldSaveFromKey = defaultShouldSaveFromKey,
strict,
},
state: { highlightedIndex, originalItem, isOpen, value },
},
e,
) {
let { onKeyDown } = inputProps || {};
// If the dropdown is open, an item is highlighted, and the user
// pressed enter, always capture that and handle it ourselves
if (isOpen) {
if (e.key === 'Enter') {
if (highlightedIndex != null) {
if (inst.lastChangeType === Downshift.stateChangeTypes.itemMouseEnter) {
// If the last thing the user did was hover an item, intentionally
// ignore the default behavior of selecting the item. It's too
// common to accidentally hover an item and then save it
e.preventDefault();
} else {
// Otherwise, stop propagation so that the table navigator
// doesn't handle it
e.stopPropagation();
}
} else if (!strict) {
// Handle it ourselves
e.stopPropagation();
onSelect(value);
return onSelectAfter(suggestions, clearAfterSelect);
} else {
// No highlighted item, still allow the table to save the item
// as `null`, even though we're allowing the table to move
e.preventDefault();
onKeyDown && onKeyDown(e);
}
} else if (shouldSaveFromKey(e)) {
e.preventDefault();
onKeyDown && onKeyDown(e);
}
}
// Handle escape ourselves
if (e.key === 'Escape') {
e.preventDefault();
if (!embedded) {
e.stopPropagation();
}
let filteredSuggestions = initialFilterSuggestions
? initialFilterSuggestions(suggestions, getItemName(originalItem))
: null;
fireUpdate(onUpdate, strict, suggestions, null, getItemId(originalItem));
return {
value: getItemName(originalItem),
selectedItem: findItem(strict, suggestions, originalItem),
filteredSuggestions,
highlightedIndex: null,
isOpen: embedded ? true : false,
};
}
} }
function defaultRenderInput(props) { function defaultRenderInput(props) {
...@@ -405,100 +100,198 @@ function defaultShouldSaveFromKey(e) { ...@@ -405,100 +100,198 @@ function defaultShouldSaveFromKey(e) {
return e.code === 'Enter'; return e.code === 'Enter';
} }
function onFocus({ props: { inputProps = {}, openOnFocus = true } }, e) {
inputProps.onFocus && inputProps.onFocus(e);
if (openOnFocus) {
return { isOpen: true };
}
}
function onBlur({ props, state: { selectedItem } }, e) {
let { inputProps = {}, onSelect } = props;
e.preventDownshiftDefault = true;
inputProps.onBlur && inputProps.onBlur(e);
if (!props.tableBehavior) {
if (e.target.value === '') {
onSelect && onSelect(null);
return { selectedItem: null, originalValue: null, isOpen: false };
}
// If not using table behavior, reset the input on blur. Tables
// handle saving the value on blur.
let value = selectedItem ? getItemId(selectedItem) : null;
return getInitialState({
props: {
...props,
value,
originalValue: value,
},
});
} else {
return { isOpen: false };
}
}
function defaultItemToString(item) { function defaultItemToString(item) {
return item ? getItemName(item) : ''; return item ? getItemName(item) : '';
} }
function SingleAutocomplete(props) { function SingleAutocomplete({
const [curState, setState] = React.useState(() => getInitialState({ props })); focused,
const { value, selectedItem, filteredSuggestions, highlightedIndex, isOpen } = embedded = false,
curState; containerProps,
inputProps = {},
suggestions,
tooltipStyle,
tooltipProps,
renderInput = defaultRenderInput,
renderItems = defaultRenderItems,
itemToString = defaultItemToString,
shouldSaveFromKey = defaultShouldSaveFromKey,
filterSuggestions = defaultFilterSuggestions,
openOnFocus = true,
getHighlightedIndex,
highlightFirst,
onUpdate,
strict,
onSelect,
tableBehavior,
value: initialValue,
}) {
const [selectedItem, setSelectedItem] = useState(() =>
findItem(strict, suggestions, initialValue),
);
const [value, setValue] = useState(
selectedItem ? getItemName(selectedItem) : '',
);
const [isChanged, setIsChanged] = useState(false);
const [originalItem, setOriginalItem] = useState(selectedItem);
const filteredSuggestions = useMemo(
() => filterSuggestions(suggestions, value),
[filterSuggestions, suggestions, value],
);
const [highlightedIndex, setHighlightedIndex] = useState(null);
const [isOpen, setIsOpen] = useState(embedded);
const prevProps = usePrevious(props); // Update the selected item if the suggestion list or initial
React.useEffect(() => { // input value has changed
if (!prevProps) return; useEffect(() => {
setSelectedItem(findItem(strict, suggestions, initialValue));
}, [initialValue, suggestions, strict]);
function resetState(newValue) {
const val = newValue === undefined ? initialValue : newValue;
let selectedItem = findItem(strict, suggestions, val);
setSelectedItem(selectedItem);
setValue(selectedItem ? getItemName(selectedItem) : '');
setOriginalItem(selectedItem);
setHighlightedIndex(null);
setIsOpen(embedded);
setIsChanged(false);
}
const newState = componentWillReceiveProps( function onSelectAfter() {
{ props: prevProps, state: curState }, setValue('');
props, setSelectedItem(null);
); setHighlightedIndex(null);
setIsChanged(false);
}
if (newState) { const filtered = isChanged ? filteredSuggestions || suggestions : suggestions;
setState(Object.assign({}, curState, newState));
}
}, [props, prevProps]);
const updater =
operation =>
(...arg) => {
const newState = Object.assign(
{},
curState,
operation({ props, state: curState }, ...arg) || {},
);
setState(newState);
};
const {
focused,
embedded,
containerProps,
inputProps,
suggestions,
tooltipStyle,
tooltipProps,
renderInput = defaultRenderInput,
renderItems = defaultRenderItems,
itemToString = defaultItemToString,
} = props;
const filtered = filteredSuggestions || suggestions;
return ( return (
<Downshift <Downshift
onSelect={updater(onSelect)} onSelect={(item, { inputValue }) => {
setSelectedItem(item);
setHighlightedIndex(null);
setIsOpen(false);
if (onSelect) {
// I AM NOT PROUD OF THIS OK??
// This WHOLE FILE is a mess anyway
// OK SIT DOWN AND I WILL EXPLAIN
// This component uses `componentWillReceiveProps` and in there
// it will re-filter suggestions if the suggestions change and
// a `highlightedIndex` exists. When we select something,
// we clear `highlightedIndex` so it should show all suggestions
// again. HOWEVER, in the case of a multi-autocomplete, it's
// changing the suggestions every time something is selected.
// In that case, cWRP is running *before* our state setting that
// cleared `highlightedIndex`. Forcing this to run later assures
// us that we will clear out local state before cWRP runs.
// YEAH THAT'S ALL OK I JUST WANT TO SHIP THIS
setTimeout(() => {
onSelect(getItemId(item), inputValue);
}, 0);
}
}}
highlightedIndex={highlightedIndex} highlightedIndex={highlightedIndex}
selectedItem={selectedItem || null} selectedItem={selectedItem || null}
itemToString={itemToString} itemToString={itemToString}
inputValue={value} inputValue={value}
isOpen={isOpen} isOpen={isOpen}
onInputValueChange={updater(onInputValueChange)} onInputValueChange={(value, changes) => {
onStateChange={updater(onStateChange)} // OMG this is the dumbest thing ever. I need to remove Downshift
// and build my own component. For some reason this is fired on blur
// with an empty value which clears out the input when the app blurs
if (!document.hasFocus()) {
return;
}
// Do nothing if it's simply updating the selected item
if (
changes.type ===
Downshift.stateChangeTypes.controlledPropUpdatedSelectedItem
) {
return;
}
// Otherwise, filter the items and always the first item if
// desired
const filteredSuggestions = filterSuggestions(suggestions, value);
if (value === '') {
// A blank value shouldn't highlight any item so that the field
// can be left blank if desired
if (changes.type !== Downshift.stateChangeTypes.clickItem) {
fireUpdate(onUpdate, strict, filteredSuggestions, null, null);
}
setHighlightedIndex(null);
} else {
let defaultGetHighlightedIndex = filteredSuggestions => {
return highlightFirst && filteredSuggestions.length ? 0 : null;
};
let highlightedIndex = (
getHighlightedIndex || defaultGetHighlightedIndex
)(filteredSuggestions);
if (changes.type !== Downshift.stateChangeTypes.clickItem) {
fireUpdate(
onUpdate,
strict,
filteredSuggestions,
highlightedIndex,
value,
);
}
setHighlightedIndex(highlightedIndex);
}
setValue(value);
setIsChanged(true);
}}
onStateChange={changes => {
if (
tableBehavior &&
changes.type === Downshift.stateChangeTypes.mouseUp
) {
return;
}
if ('highlightedIndex' in changes) {
setHighlightedIndex(changes.highlightedIndex);
}
if ('isOpen' in changes) {
setIsOpen(embedded ? true : changes.isOpen);
}
if ('selectedItem' in changes) {
setSelectedItem(changes.selectedItem);
}
// We only ever want to update the value if the user explicitly
// highlighted an item via the keyboard. It shouldn't change with
// mouseover; otherwise the user could accidentally hover over an
// item without realizing it and change the value.
if (
isOpen &&
(changes.type === Downshift.stateChangeTypes.keyDownArrowUp ||
changes.type === Downshift.stateChangeTypes.keyDownArrowDown)
) {
fireUpdate(
onUpdate,
strict,
filteredSuggestions || suggestions,
changes.highlightedIndex != null
? changes.highlightedIndex
: highlightedIndex,
value,
);
}
inst.lastChangeType = changes.type;
}}
> >
{({ {({
getInputProps, getInputProps,
...@@ -518,10 +311,98 @@ function SingleAutocomplete(props) { ...@@ -518,10 +311,98 @@ function SingleAutocomplete(props) {
getInputProps({ getInputProps({
focused, focused,
...inputProps, ...inputProps,
onFocus: updater(onFocus), onFocus: e => {
onBlur: updater(onBlur), inputProps.onFocus && inputProps.onFocus(e);
onKeyDown: updater(onKeyDown),
onChange: updater(onChange), if (openOnFocus) {
setIsOpen(true);
}
},
onBlur: e => {
e.preventDownshiftDefault = true;
inputProps.onBlur && inputProps.onBlur(e);
if (!tableBehavior) {
if (e.target.value === '') {
onSelect && onSelect(null, e.target.value);
setSelectedItem(null);
setIsOpen(false);
return;
}
// If not using table behavior, reset the input on blur. Tables
// handle saving the value on blur.
let value = selectedItem ? getItemId(selectedItem) : null;
resetState(value);
} else {
setIsOpen(false);
}
},
onKeyDown: e => {
let { onKeyDown } = inputProps || {};
// If the dropdown is open, an item is highlighted, and the user
// pressed enter, always capture that and handle it ourselves
if (isOpen) {
if (e.key === 'Enter') {
if (highlightedIndex != null) {
if (
inst.lastChangeType ===
Downshift.stateChangeTypes.itemMouseEnter
) {
// If the last thing the user did was hover an item, intentionally
// ignore the default behavior of selecting the item. It's too
// common to accidentally hover an item and then save it
e.preventDefault();
} else {
// Otherwise, stop propagation so that the table navigator
// doesn't handle it
e.stopPropagation();
}
} else if (!strict) {
// Handle it ourselves
e.stopPropagation();
onSelect(value, e.target.value);
return onSelectAfter();
} else {
// No highlighted item, still allow the table to save the item
// as `null`, even though we're allowing the table to move
e.preventDefault();
onKeyDown && onKeyDown(e);
}
} else if (shouldSaveFromKey(e)) {
e.preventDefault();
onKeyDown && onKeyDown(e);
}
}
// Handle escape ourselves
if (e.key === 'Escape') {
e.preventDefault();
if (!embedded) {
e.stopPropagation();
}
fireUpdate(
onUpdate,
strict,
suggestions,
null,
getItemId(originalItem),
);
setValue(getItemName(originalItem));
setSelectedItem(findItem(strict, suggestions, originalItem));
setHighlightedIndex(null);
setIsOpen(embedded ? true : false);
}
},
onChange: e => {
const { onChange } = inputProps || {};
onChange && onChange(e.target.value);
},
}), }),
)} )}
{isOpen && {isOpen &&
...@@ -624,7 +505,6 @@ export function MultiAutocomplete({ ...@@ -624,7 +505,6 @@ export function MultiAutocomplete({
item => !selectedItems.includes(getItemId(item)), item => !selectedItems.includes(getItemId(item)),
)} )}
onSelect={onAddItem} onSelect={onAddItem}
clearAfterSelect
highlightFirst highlightFirst
strict={strict} strict={strict}
tooltipProps={{ tooltipProps={{
......
import React, { useState, useMemo, useRef } from 'react'; import React, { useState, useMemo } from 'react';
import { useDispatch } from 'react-redux'; import { useDispatch } from 'react-redux';
import { createPayee } from 'loot-core/src/client/actions/queries'; import { createPayee } from 'loot-core/src/client/actions/queries';
...@@ -27,8 +27,8 @@ function getPayeeSuggestions(payees, focusTransferPayees, accounts) { ...@@ -27,8 +27,8 @@ function getPayeeSuggestions(payees, focusTransferPayees, accounts) {
} }
function makeNew(value, rawPayee) { function makeNew(value, rawPayee) {
if (value === 'new' && !rawPayee.current.startsWith('new:')) { if (value === 'new' && !rawPayee.startsWith('new:')) {
return 'new:' + rawPayee.current; return 'new:' + rawPayee;
} }
return value; return value;
} }
...@@ -189,22 +189,28 @@ export default function PayeeAutocomplete({ ...@@ -189,22 +189,28 @@ export default function PayeeAutocomplete({
let [focusTransferPayees, setFocusTransferPayees] = useState( let [focusTransferPayees, setFocusTransferPayees] = useState(
defaultFocusTransferPayees, defaultFocusTransferPayees,
); );
let payeeSuggestions = useMemo( let [rawPayee, setRawPayee] = useState('');
() => [ let hasPayeeInput = !!rawPayee;
{ id: 'new', name: '' }, let payeeSuggestions = useMemo(() => {
...getPayeeSuggestions(payees, focusTransferPayees, accounts), const suggestions = getPayeeSuggestions(
], payees,
[payees, focusTransferPayees, accounts], focusTransferPayees,
); accounts,
);
if (!hasPayeeInput) {
return suggestions;
}
return [{ id: 'new', name: '' }, ...suggestions];
}, [payees, focusTransferPayees, accounts, hasPayeeInput]);
let rawPayee = useRef('');
let dispatch = useDispatch(); let dispatch = useDispatch();
async function handleSelect(value) { async function handleSelect(value, rawInputValue) {
if (tableBehavior) { if (tableBehavior) {
onSelect && onSelect(makeNew(value, rawPayee)); onSelect && onSelect(makeNew(value, rawInputValue));
} else { } else {
let create = () => dispatch(createPayee(rawPayee.current)); let create = () => dispatch(createPayee(rawInputValue));
if (Array.isArray(value)) { if (Array.isArray(value)) {
value = await Promise.all(value.map(v => (v === 'new' ? create() : v))); value = await Promise.all(value.map(v => (v === 'new' ? create() : v)));
...@@ -231,18 +237,23 @@ export default function PayeeAutocomplete({ ...@@ -231,18 +237,23 @@ export default function PayeeAutocomplete({
if (!item) { if (!item) {
return ''; return '';
} else if (item.id === 'new') { } else if (item.id === 'new') {
return rawPayee.current; return rawPayee;
} }
return item.name; return item.name;
}} }}
focused={payeeFieldFocused} focused={payeeFieldFocused}
inputProps={{ inputProps={{
...inputProps, ...inputProps,
onBlur: () => setPayeeFieldFocused(false), onBlur: () => {
setRawPayee('');
setPayeeFieldFocused(false);
},
onFocus: () => setPayeeFieldFocused(true), onFocus: () => setPayeeFieldFocused(true),
onChange: text => (rawPayee.current = text), onChange: setRawPayee,
}} }}
onUpdate={value => onUpdate && onUpdate(makeNew(value, rawPayee))} onUpdate={(value, inputValue) =>
onUpdate && onUpdate(makeNew(value, inputValue))
}
onSelect={handleSelect} onSelect={handleSelect}
getHighlightedIndex={suggestions => { getHighlightedIndex={suggestions => {
if (suggestions.length > 1 && suggestions[0].id === 'new') { if (suggestions.length > 1 && suggestions[0].id === 'new') {
...@@ -251,7 +262,7 @@ export default function PayeeAutocomplete({ ...@@ -251,7 +262,7 @@ export default function PayeeAutocomplete({
return 0; return 0;
}} }}
filterSuggestions={(suggestions, value) => { filterSuggestions={(suggestions, value) => {
let filtered = suggestions.filter((suggestion, idx) => { let filtered = suggestions.filter(suggestion => {
if (suggestion.id === 'new') { if (suggestion.id === 'new') {
return !value || value === '' || focusTransferPayees ? false : true; return !value || value === '' || focusTransferPayees ? false : true;
} }
...@@ -301,26 +312,6 @@ export default function PayeeAutocomplete({ ...@@ -301,26 +312,6 @@ export default function PayeeAutocomplete({
} }
return filtered; return filtered;
}} }}
initialFilterSuggestions={suggestions => {
let filtered = false;
let res = suggestions.filter((suggestion, idx) => {
if (suggestion.id === 'new') {
// Never show the "create new" initially
return false;
}
if (idx >= 100 && !suggestion.transfer_acct) {
filtered = true;
return false;
}
return true;
});
if (filtered) {
res.filtered = true;
}
return res;
}}
renderItems={(items, getItemProps, highlightedIndex, inputValue) => ( renderItems={(items, getItemProps, highlightedIndex, inputValue) => (
<PayeeList <PayeeList
items={items} items={items}
......
...@@ -45,23 +45,21 @@ export default function GenericInput({ ...@@ -45,23 +45,21 @@ export default function GenericInput({
case 'id': case 'id':
switch (field) { switch (field) {
case 'payee': case 'payee':
if (payees.length > 0) { content = (
content = ( <PayeeAutocomplete
<PayeeAutocomplete payees={payees}
payees={payees} accounts={accounts}
accounts={accounts} multi={multi}
multi={multi} showMakeTransfer={false}
showMakeTransfer={false} openOnFocus={true}
openOnFocus={true} value={value}
value={value} onSelect={onChange}
onSelect={onChange} inputProps={{
inputProps={{ inputRef,
inputRef, ...(showPlaceholder ? { placeholder: 'nothing' } : null),
...(showPlaceholder ? { placeholder: 'nothing' } : null), }}
}} />
/> );
);
}
break; break;
case 'account': case 'account':
......
---
category: Maintenance
authors: [MatissJanis]
---
Cleaning up state management in autocomplete
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment