Skip to content

Commit

Permalink
[JN-1539] fixing portal select in create user (#1335)
Browse files Browse the repository at this point in the history
  • Loading branch information
devonbush authored Dec 16, 2024
1 parent 9b5a10b commit abad83b
Show file tree
Hide file tree
Showing 2 changed files with 77 additions and 17 deletions.
40 changes: 40 additions & 0 deletions ui-admin/src/user/CreateUserModal.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react'
import { mockPortal, renderInPortalRouter } from 'test-utils/mocking-utils'
import { screen } from '@testing-library/react'
import { mockAdminUser } from '../test-utils/user-mocking-utils'
import Api from 'api/api'
import CreateUserModal from './CreateUserModal'
import { userEvent } from '@testing-library/user-event'
import { select } from 'react-select-event'

describe('CreateUserModal', () => {
test('Portal select functions', async () => {
jest.spyOn(Api, 'fetchRoles').mockResolvedValue([])
const createSpy = jest.spyOn(Api, 'createPortalUser').mockResolvedValue(mockAdminUser(false))
const portals = [{
...mockPortal(),
shortcode: 'test1',
name: 'P1'
}, {
...mockPortal(),
shortcode: 'test2',
name: 'P2'
}]

renderInPortalRouter(portals[1],
<CreateUserModal onDismiss={jest.fn()} portals={portals} userCreated={jest.fn()} />)
await userEvent.type(screen.getByLabelText('Email'), '[email protected]')
await userEvent.click(screen.getByText('Create'))

expect(createSpy).toHaveBeenCalledWith({
username: '[email protected]', superuser: false, portalShortcode: 'test1', roleNames: []
})

createSpy.mockClear()
await select(screen.getByLabelText('Portal'), ['P2'])
await userEvent.click(screen.getByText('Create'))
expect(createSpy).toHaveBeenCalledWith({
username: '[email protected]', superuser: false, portalShortcode: 'test2', roleNames: []
})
})
})
54 changes: 37 additions & 17 deletions ui-admin/src/user/CreateUserModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,33 +9,36 @@ import { Store } from 'react-notifications-component'
import Select from 'react-select'
import { doApiLoad, useLoadingEffect } from '../api/api-utils'
import { RoleSelector } from './AdminUserDetail'
import useReactSingleSelect from '../util/react-select-utils'

const DEFAULT_ROLE = 'study_admin'

/** creates a new admin user */
const CreateUserModal = ({ onDismiss, portals, userCreated }:
{ onDismiss: () => void,
portals: Portal[], userCreated: () => void
}) => {
const [isLoading, setIsLoading] = useState(false)
const [portalShortcode, setPortalShortcode] =
useState<string | null>(portals.length > 0 ? portals[0].shortcode : null)
const { user } = useUser()
const [newUser, setNewUser] = useState<AdminUserParams>({
username: '',
superuser: false,
portalShortcode,
roleNames: ['study_admin']
portalShortcode: portals.length > 0 ? portals[0].shortcode : null,
roleNames: []
})
const portalOpts = portals.map(portal => ({ label: portal.name, value: portal.shortcode }))
const selectedPortalOpt = portalOpts.find(portalOpt => portalOpt.value === portalShortcode)
const [roles, setRoles] = useState<Role[]>([])

useLoadingEffect(async () => {
const { isLoading: rolesLoading } = useLoadingEffect(async () => {
const fetchedRoles = await Api.fetchRoles()
setNewUser({
...newUser,
roleNames: fetchedRoles.filter(role => role.name === DEFAULT_ROLE).map(role => role.name)
})
setRoles(fetchedRoles)
})

const createUser = async () => {
doApiLoad(async () => {
await doApiLoad(async () => {
let createdUser: AdminUser
if (!newUser.superuser) {
createdUser = await Api.createPortalUser(newUser)
Expand All @@ -59,12 +62,12 @@ const CreateUserModal = ({ onDismiss, portals, userCreated }:
<form onSubmit={e => e.preventDefault()}>
<div className="py-2">
<div className="mb-3">
<label className="form-label">
<label className="form-label d-block">
Email
<input type="email" value={newUser.username} className="form-control"
onChange={e => setNewUser({ ...newUser, username: e.target.value })}/>
<span className="form-text">Email must be a Microsoft- or Google-based account</span>
</label>
<span className="form-text ps-3">Email must be a Microsoft- or Google-based account</span>
</div>
{user?.superuser && <div className="mb-3">
<span>Superuser</span><br/>
Expand All @@ -79,12 +82,13 @@ const CreateUserModal = ({ onDismiss, portals, userCreated }:
</label>
</div> }
{ !newUser.superuser && <div>
<div>
<label className="w-100 mb-3">
Portal
<Select options={portalOpts} value={selectedPortalOpt} isDisabled={portalOpts.length < 2}
onChange={opt => setPortalShortcode(opt?.value ?? null)}/>
</label>
<div className="mb-3">
<PortalSelector portals={portals}
selectedPortal={portals.find(p => p.shortcode === newUser.portalShortcode)}
setSelectedPortal={portal => setNewUser({
...newUser,
portalShortcode: portal?.shortcode ?? null
})}/>
</div>
<div>
<RoleSelector roles={roles} selectedRoleNames={newUser.roleNames} setSelectedRoleNames={roleNames =>
Expand All @@ -95,7 +99,7 @@ const CreateUserModal = ({ onDismiss, portals, userCreated }:
</form>
</Modal.Body>
<Modal.Footer>
<LoadingSpinner isLoading={isLoading}>
<LoadingSpinner isLoading={isLoading || rolesLoading}>
<button className="btn btn-primary" onClick={createUser} disabled={!isUserValid}>Create</button>
<button className="btn btn-secondary" onClick={onDismiss}>Cancel</button>
</LoadingSpinner>
Expand All @@ -104,3 +108,19 @@ const CreateUserModal = ({ onDismiss, portals, userCreated }:
}

export default CreateUserModal

export const PortalSelector = ({ portals, selectedPortal, setSelectedPortal }: {
portals: Portal[], selectedPortal?: Portal, setSelectedPortal: (portal?: Portal) => void
}) => {
const { onChange, options, selectedOption, selectInputId } = useReactSingleSelect<Portal>(portals,
portal => ({ label: portal.name, value: portal }),
(opt: Portal | undefined) => setSelectedPortal(opt),
portals.find(portal => portal.shortcode === selectedPortal?.shortcode))

return <>
<label className="form-label" htmlFor={selectInputId}>
Portal
</label>
<Select options={options} value={selectedOption} onChange={onChange} inputId={selectInputId}/>
</>
}

0 comments on commit abad83b

Please sign in to comment.