Skip to content

Commit 4f572cd

Browse files
committed
replaced memberIds input with autocomplete
1 parent 554a51b commit 4f572cd

File tree

1 file changed

+29
-18
lines changed

1 file changed

+29
-18
lines changed

packages/groups/src/components/Form.jsx

Lines changed: 29 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88

99
import { useEffect, useReducer } from 'react'
1010
import { useNavigate, useParams } from 'react-router-dom'
11-
import { useServices } from '@kernel/common'
11+
import { useServices, AutocompleteInput, errorUtils } from '@kernel/common'
1212

1313
import AppConfig from 'App.config'
1414

1515
const MODES = { create: 'create', update: 'update' }
16-
const KEYS = ['name', 'memberIdsText']
17-
const STATE_KEYS = ['group', 'groups', 'member', 'members', 'error', 'status', 'taskService']
16+
const KEYS = ['name', 'memberIdsText', 'groupMembers']
17+
const STATE_KEYS = ['group', 'groups', 'member', 'members', 'profiles', 'error', 'status', 'taskService']
1818
const INITIAL_STATE = STATE_KEYS.concat(KEYS)
1919
.reduce((acc, k) => Object.assign(acc, { [k]: '' }), {})
2020

@@ -23,6 +23,8 @@ Object.keys(INITIAL_STATE)
2323
.forEach((k) => {
2424
actions[k] = (state, e) => Object.assign({}, state, { [k]: e })
2525
})
26+
INITIAL_STATE.groupMembers = []
27+
INITIAL_STATE.profiles = []
2628

2729
const reducer = (state, action) => {
2830
try {
@@ -50,8 +52,8 @@ const value = (state, type) => {
5052
}
5153

5254
// dedupe, sort
53-
const textToArray = (s) => [...new Set(s.split(',').map((e) => e.trim()))].sort()
54-
const arrayToText = (arr) => arr.join(', ')
55+
const getMemberIds = (groupMembers) => groupMembers.map(groupMember => groupMember.id)
56+
const transformProfiles = (profiles) => Object.values(profiles).map(({ data: { memberId, name } }) => ({ id: memberId, name }))
5557
const resetAlerts = (dispatch) => {
5658
dispatch({ type: 'error', payload: '' })
5759
dispatch({ type: 'status', payload: 'submitting' })
@@ -60,9 +62,9 @@ const resetAlerts = (dispatch) => {
6062
const create = async (state, dispatch, e) => {
6163
e.preventDefault()
6264
resetAlerts(dispatch)
63-
const { groups, memberIdsText, name, taskService } = state
64-
const memberIds = textToArray(memberIdsText)
65-
if (!name.length || !memberIdsText.length) {
65+
const { groups, groupMembers, name, taskService } = state
66+
const memberIds = getMemberIds(groupMembers)
67+
if (!name.length || !groupMembers.length) {
6668
dispatch({ type: 'error', payload: 'name and member ids are required' })
6769
return
6870
}
@@ -80,9 +82,9 @@ const create = async (state, dispatch, e) => {
8082
const update = async (state, dispatch, e) => {
8183
e.preventDefault()
8284
resetAlerts(dispatch)
83-
const { group, groups, memberIdsText, name, taskService } = state
85+
const { group, groups, groupMembers, name, taskService } = state
8486
const groupId = group.id
85-
const memberIds = textToArray(memberIdsText)
87+
const memberIds = getMemberIds(groupMembers)
8688
try {
8789
if (group.data.name !== name) {
8890
await groups.patch(groupId, { name })
@@ -107,6 +109,7 @@ const Form = () => {
107109

108110
const { services, currentUser } = useServices()
109111
const user = currentUser()
112+
const { readable } = errorUtils
110113

111114
useEffect(() => {
112115
if (!user || user.role > AppConfig.minRole) {
@@ -117,14 +120,22 @@ const Form = () => {
117120
useEffect(() => {
118121
(async () => {
119122
dispatch({ type: 'status', payload: 'Loading' })
120-
const { entityFactory, taskService } = await services()
123+
const { entityFactory, taskService, queryService } = await services()
121124
dispatch({ type: 'taskService', payload: taskService })
122125
const members = await entityFactory({ resource: 'member' })
123126
const member = await members.get(user.iss)
124127
const groups = await entityFactory({ resource: 'group' })
128+
let transformedProfiles = []
129+
try {
130+
const { profiles } = await queryService.recommend()
131+
transformedProfiles = transformProfiles(profiles)
132+
} catch (error) {
133+
dispatch({ type: 'error', payload: readable(error.message) })
134+
}
125135
dispatch({ type: 'members', payload: members })
126136
dispatch({ type: 'member', payload: member })
127137
dispatch({ type: 'groups', payload: groups })
138+
dispatch({ type: 'profiles', payload: transformedProfiles })
128139
if (mode === MODES.update) {
129140
const entity = await groups.get(group)
130141
dispatch({ type: 'group', payload: entity })
@@ -133,10 +144,9 @@ const Form = () => {
133144
.forEach(([k, v]) => {
134145
let type = k
135146
let payload = v
136-
// TODO: more ergonomic way to select group memebers
137147
if (k === 'memberIds') {
138-
type = 'memberIdsText'
139-
payload = arrayToText(v)
148+
type = 'groupMembers'
149+
payload = transformedProfiles.filter(item => v.includes(item.id))
140150
}
141151
dispatch({ type, payload })
142152
})
@@ -155,10 +165,11 @@ const Form = () => {
155165
/>
156166
</label>
157167
<label className='block'>
158-
<span className='text-gray-700'>Member Ids (comma separated)</span>
159-
<input
160-
type='text' multiple className={formClass}
161-
value={value(state, 'memberIdsText')} onChange={change.bind(null, dispatch, 'memberIdsText')}
168+
<span className='text-gray-700'>Member Names</span>
169+
<AutocompleteInput
170+
items={value(state, 'profiles')}
171+
selectedItems={value(state, 'groupMembers')}
172+
setSelectedItems={items => dispatch({ type: 'groupMembers', payload: items })}
162173
/>
163174
</label>
164175
<label className='block'>

0 commit comments

Comments
 (0)