From 45f55912ac4f4ad2b2046b1ffcb7fd862c1b8955 Mon Sep 17 00:00:00 2001 From: Maksym Mykhailenko Date: Wed, 13 Feb 2019 16:57:39 +0800 Subject: [PATCH 1/2] winning submission from challenge 30083313 - Topcoder Connect - Team Management - Autocomplete --- .../TeamManagement/AutocompleteInput.jsx | 109 +++++++++++++++++ .../TeamManagement/AutocompleteInput.scss | 41 +++++++ .../TeamManagement/ProjectManagementDialog.js | 111 ++++++++---------- .../TeamManagement/TeamManagement.jsx | 21 +++- .../TeamManagement/TeamManagement.scss | 8 +- .../TopcoderManagementDialog.js | 104 ++++++++-------- .../containers/TeamManagementContainer.jsx | 92 ++++++++++++--- 7 files changed, 341 insertions(+), 145 deletions(-) create mode 100644 src/components/TeamManagement/AutocompleteInput.jsx create mode 100644 src/components/TeamManagement/AutocompleteInput.scss diff --git a/src/components/TeamManagement/AutocompleteInput.jsx b/src/components/TeamManagement/AutocompleteInput.jsx new file mode 100644 index 000000000..2f5eb56f5 --- /dev/null +++ b/src/components/TeamManagement/AutocompleteInput.jsx @@ -0,0 +1,109 @@ +import React from 'react' +import PropTypes from 'prop-types' +import {findIndex} from 'lodash' +import Select from '../Select/Select' +import './AutocompleteInput.scss' +import {loadMemberSuggestions} from '../../api/projectMembers' +import {AUTOCOMPLETE_TRIGGER_LENGTH} from '../../config/constants' + +/** + * Render a searchable dropdown for selecting users that can be invited + */ +const AutocompleteInput = ({ + onUpdate, + placeholder, + selectedMembers, + disabled, + allMembers, +}) => { + const onChange = (inputValue, selectedOptions = []) => { + + if (onUpdate) { + onUpdate(selectedOptions) + } + } + + const asyncOptions = (input) => { + const value = typeof input === 'string' ? input : '' + const createOption = { + handle: value, + // Decide if it's email + isEmail: (/(.+)@(.+){2,}\.(.+){2,}/).test(value), + } + if (value.length >= AUTOCOMPLETE_TRIGGER_LENGTH) { + return loadMemberSuggestions(value).then(r => { + // Remove current members from suggestions + const suggestions = r.filter(suggestion => ( + findIndex(allMembers, (member) => member.handle === suggestion.handle) === -1 && + // Remove current value from list to add it manually on top + suggestion.handle !== value + )) + // Only allow creation if it is not already exists in members + const shouldIncludeCreateOption = findIndex(allMembers, (member) => member.handle === value) === -1 + + return Promise.resolve({options: shouldIncludeCreateOption?[createOption, ...suggestions]: suggestions}) + }).catch( () => { + return Promise.resolve({options: [createOption] }) + }) + } + return Promise.resolve({options: value.length > 0 ? [createOption] : []}) + } + + return ( +
+ -
- ) + render() { + const { + placeholder, + selectedMembers, + disabled, + } = this.props + + return ( +
+