import React, { useEffect, useState } from "react"; import { Dropdown, Label, Loader, Message, Icon, DropdownItemProps, DropdownOnSearchChangeData, DropdownProps } from "semantic-ui-react"; import { getFormErrorLabelsProps } from "./errorHandling"; import * as Yup from "yup"; import { GenericProposalForm, GenericFormValues, genericFormDefaultOptions, genericFormDefaultValues, withProposalFormData, ProposalFormExportProps, ProposalFormContainerProps, ProposalFormInnerProps } from "./GenericProposalForm"; import Validation from "../validationSchema"; import { FormField } from "./FormFields"; import { withFormContainer } from "./FormContainer"; import { useTransport } from "../runtime"; import { usePromise } from "../utils"; import { Profile } from "@joystream/types/members"; import PromiseComponent from "../Proposal/PromiseComponent"; import _ from 'lodash'; import "./forms.css"; type FormValues = GenericFormValues & { workingGroupLead: any; }; const defaultValues: FormValues = { ...genericFormDefaultValues, workingGroupLead: "" }; type FormAdditionalProps = {}; // Aditional props coming all the way from export comonent into the inner form. type ExportComponentProps = ProposalFormExportProps; type FormContainerProps = ProposalFormContainerProps; type FormInnerProps = ProposalFormInnerProps; function memberOptionKey(id: number, profile: Profile) { return `${id}:${profile.root_account.toString()}`; } const MEMBERS_QUERY_MIN_LENGTH = 4; const MEMBERS_NONE_OPTION: DropdownItemProps = { key: '- NONE -', text: '- NONE -', value: 'none' } function membersToOptions(members: { id: number, profile: Profile }[]) { return [MEMBERS_NONE_OPTION].concat( members .map(({ id, profile }) => ({ key: profile.handle, text: `${ profile.handle } (id:${ id })`, value: memberOptionKey(id, profile), image: profile.avatar_uri.toString() ? { avatar: true, src: profile.avatar_uri } : null })) ); } function filterMembers(options: DropdownItemProps[], query: string) { if (query.length < MEMBERS_QUERY_MIN_LENGTH) { return [MEMBERS_NONE_OPTION]; } const regexp = new RegExp(_.escapeRegExp(query)); return options.filter((opt) => regexp.test((opt.text || '').toString())) } type MemberWithId = { id: number; profile: Profile }; const SetContentWorkingGroupsLeadForm: React.FunctionComponent = props => { const { handleChange, errors, touched, values } = props; const errorLabelsProps = getFormErrorLabelsProps(errors, touched); // State const [ membersOptions, setMembersOptions ] = useState([] as DropdownItemProps[]); const [ filteredOptions, setFilteredOptions ] = useState([] as DropdownItemProps[]); const [ membersSearchQuery, setMembersSearchQuery ] = useState(""); // Transport const transport = useTransport(); const [members, /* error */, loading] = usePromise( () => transport.membersExceptCouncil(), [] ); const [currentLead, clError, clLoading] = usePromise( () => transport.WGLead(), null ); // Generate members options array on load useEffect(() => { if (members.length) { setMembersOptions(membersToOptions(members)); } }, [members]); // Filter options on search query change (we "pulled-out" this logic here to avoid lags) useEffect(() => { setFilteredOptions(filterMembers(membersOptions, membersSearchQuery)); }, [membersSearchQuery]); return ( {loading ? ( <> Fetching members... ) : (<> { (!values.workingGroupLead || membersSearchQuery.length > 0) && (MEMBERS_QUERY_MIN_LENGTH - membersSearchQuery.length) > 0 && ( ) } options } // On search change we update it in our state onSearchChange={ (e: React.SyntheticEvent, data: DropdownOnSearchChangeData) => { setMembersSearchQuery(data.searchQuery); } } name="workingGroupLead" placeholder={ "Start typing member handle or \"id:[ID]\" query..." } fluid selection options={filteredOptions} onChange={ (e: React.ChangeEvent, data: DropdownProps) => { // Fix TypeScript issue const originalHandler = handleChange as (e: React.ChangeEvent, data: DropdownProps) => void; originalHandler(e, data); if (!data.value) { setMembersSearchQuery(''); } } } value={values.workingGroupLead} /> {errorLabelsProps.workingGroupLead && Current Content Working Group lead: { (currentLead && currentLead.profile.handle) || 'NONE' } )} ); }; const FormContainer = withFormContainer({ mapPropsToValues: (props: FormContainerProps) => ({ ...defaultValues, ...(props.initialData || {}) }), validationSchema: Yup.object().shape({ ...genericFormDefaultOptions.validationSchema, workingGroupLead: Validation.SetLead.workingGroupLead }), handleSubmit: genericFormDefaultOptions.handleSubmit, displayName: "SetContentWorkingGroupLeadForm" })(SetContentWorkingGroupsLeadForm); export default withProposalFormData(FormContainer);