diff --git a/src/components/ProjectForm/GroupsFormField/index.js b/src/components/ProjectForm/GroupsFormField/index.js new file mode 100644 index 00000000..5106b2dd --- /dev/null +++ b/src/components/ProjectForm/GroupsFormField/index.js @@ -0,0 +1,74 @@ +import React, { useCallback } from 'react' +import { debounce, map } from 'lodash' +import PropTypes from 'prop-types' +import Select from '../../Select' +import { fetchGroups as fetchGroupsApi } from '../../../services/challenges' +import { AUTOCOMPLETE_DEBOUNCE_TIME_MS } from '../../../config/constants' +import { useMapSelectedGroups } from './use-map-selected-groups.hook' + +/** + * Search & fetch groups from api, filtering by group name + */ +const fetchGroups = debounce((inputValue, callback) => { + fetchGroupsApi({ name: inputValue }) + .then(groups => { + const suggestedOptions = groups.map(group => ({ + label: group.name, + value: group.id + })) + return callback(suggestedOptions) + }) + .catch(() => { + return callback(null) + }) +}, AUTOCOMPLETE_DEBOUNCE_TIME_MS) + +/** + * Component to handle project groups + */ +const GroupsFormField = ({ value, name, onBlur, onChange, id, placeholder, ref }) => { + const selectedGroups = useMapSelectedGroups(value) + + const handleChange = useCallback((values) => { + onChange({ target: { name, value: map(values, 'value') } }) + }, []) + + return ( + + ) +} + +GroupsFormField.defaultProps = { + onChange: () => {}, + onBlur: () => {}, + id: 'group-select', + value: [], + name: '', + ref: undefined, + placeholder: '' +} + +GroupsFormField.propTypes = { + value: PropTypes.arrayOf(PropTypes.shape()), + id: PropTypes.string, + onBlur: PropTypes.func, + onChange: PropTypes.func, + name: PropTypes.string, + ref: PropTypes.ref, + placeholder: PropTypes.string +} + +export default GroupsFormField diff --git a/src/components/ProjectForm/GroupsFormField/use-map-selected-groups.hook.js b/src/components/ProjectForm/GroupsFormField/use-map-selected-groups.hook.js new file mode 100644 index 00000000..edcfb706 --- /dev/null +++ b/src/components/ProjectForm/GroupsFormField/use-map-selected-groups.hook.js @@ -0,0 +1,17 @@ +import { useEffect, useState } from 'react' +import { loadGroupDetails } from '../../../actions/challenges' + +export const useMapSelectedGroups = (groupIds) => { + const [selectedGroups, setSelectedGroups] = useState([]) + useEffect(() => { + if (!groupIds || !groupIds.length) { + setSelectedGroups([]) + return + } + + loadGroupDetails(groupIds).then(res => { + setSelectedGroups(res.map(d => ({ label: d.name, value: d.id }))) + }) + }, [groupIds]) + return selectedGroups +} diff --git a/src/components/ProjectForm/ProjectForm.module.scss b/src/components/ProjectForm/ProjectForm.module.scss index 72542ad4..769e4823 100644 --- a/src/components/ProjectForm/ProjectForm.module.scss +++ b/src/components/ProjectForm/ProjectForm.module.scss @@ -59,6 +59,15 @@ form { color: $tc-gray-80; padding: 10px 20px; } + input[type=radio] { + width: 18px; + } + } + + .flexField { + display: flex; + flex-direction: row; + gap: 15px; } .error { @@ -81,3 +90,9 @@ form { } } } + +.flexRow { + display: flex; + gap: 5px; + align-items: center; +} \ No newline at end of file diff --git a/src/components/ProjectForm/index.js b/src/components/ProjectForm/index.js index 70b15d7d..9f528ea3 100644 --- a/src/components/ProjectForm/index.js +++ b/src/components/ProjectForm/index.js @@ -1,10 +1,12 @@ -import React, { useState } from 'react' +import React, { useMemo, useState } from 'react' import { useForm, Controller } from 'react-hook-form' import cn from 'classnames' +import { get } from 'lodash' import styles from './ProjectForm.module.scss' import { PrimaryButton } from '../Buttons' import Select from '../Select' -import { PROJECT_STATUS } from '../../config/constants' +import { PROJECT_STATUS, DEFAULT_NDA_UUID } from '../../config/constants' +import GroupsFormField from './GroupsFormField' const ProjectForm = ({ projectTypes, @@ -31,7 +33,9 @@ const ProjectForm = ({ : null, projectType: isEdit ? projectTypes.find((item) => item.key === projectDetail.type) || null - : null // we'll store type as an object from react-select + : null, // we'll store type as an object from react-select + terms: get(projectDetail, ['terms', 0], ''), + groups: get(projectDetail, ['groups'], []) } }) @@ -41,18 +45,18 @@ const ProjectForm = ({ setIsSaving(true) try { + const payload = { + name: data.projectName, + description: data.description, + type: data.projectType.value, + groups: data.groups, + terms: data.terms ? [data.terms] : [] + } + if (isEdit) { - await updateProject(projectDetail.id, { - name: data.projectName, - description: data.description, - status: data.status.value - }) + await updateProject(projectDetail.id, payload) } else { - const res = await createProject({ - name: data.projectName, - description: data.description, - type: data.projectType.value - }) + const res = await createProject(payload) history.push(`/projects/${res.value.id}/challenges`) setActiveProject(res.value.id) @@ -65,10 +69,10 @@ const ProjectForm = ({ } // Build options for react-select from `types` - const selectOptions = projectTypes.map((t) => ({ + const projectTypeOptions = useMemo(() => projectTypes.map((t) => ({ value: t.key, label: t.displayName - })) + })), [projectTypes]) return (