import React, { ChangeEvent, useEffect, useState } from 'react'; import { TextField, CircularProgress, Grid, Button, InputAdornment, SelectChangeEvent, } from '@mui/material'; import { Search } from '@mui/icons-material'; import Autocomplete from '@mui/material/Autocomplete'; import { ProjectRoleSelect } from '../ProjectRoleSelect/ProjectRoleSelect'; import useProjectApi from 'hooks/api/actions/useProjectApi/useProjectApi'; import useToast from 'hooks/useToast'; import useProjectAccess, { IProjectAccessUser, } from 'hooks/api/getters/useProjectAccess/useProjectAccess'; import { IProjectRole } from 'interfaces/role'; import { ConditionallyRender } from 'component/common/ConditionallyRender/ConditionallyRender'; import { useRequiredPathParam } from 'hooks/useRequiredPathParam'; interface IProjectAccessAddUserProps { roles: IProjectRole[]; } export const ProjectAccessAddUser = ({ roles }: IProjectAccessAddUserProps) => { const projectId = useRequiredPathParam('projectId'); const [user, setUser] = useState(); const [role, setRole] = useState(); const [options, setOptions] = useState([]); const [loading, setLoading] = useState(false); const { setToastData } = useToast(); const { refetchProjectAccess, access } = useProjectAccess(projectId); const { searchProjectUser, addUserToRole } = useProjectApi(); useEffect(() => { if (roles.length > 0) { const regularRole = roles.find( r => r.name.toLowerCase() === 'regular' ); setRole(regularRole || roles[0]); } }, [roles]); const search = async (query: string) => { if (query.length > 1) { setLoading(true); const result = await searchProjectUser(query); const userSearchResults = await result.json(); const filteredUsers = userSearchResults.filter( (selectedUser: IProjectAccessUser) => { const selected = access.users.find( (user: IProjectAccessUser) => user.id === selectedUser.id ); return !selected; } ); setOptions(filteredUsers); } else { setOptions([]); } setLoading(false); }; const handleQueryUpdate = (evt: { target: { value: string } }) => { const q = evt.target.value; search(q); }; const handleBlur = () => { if (options.length > 0) { const user = options[0]; setUser(user); } }; const handleSelectUser = ( evt: ChangeEvent<{}>, selectedUser: string | IProjectAccessUser | null ) => { setOptions([]); if (typeof selectedUser === 'string' || selectedUser === null) { return; } if (selectedUser?.id) { setUser(selectedUser); } }; const handleRoleChange = (evt: SelectChangeEvent) => { const roleId = Number(evt.target.value); const role = roles.find(role => role.id === roleId); if (role) { setRole(role); } }; const handleSubmit = async (evt: React.SyntheticEvent) => { evt.preventDefault(); if (!role || !user) { setToastData({ type: 'error', title: 'Invalid selection', text: `The selected user or role does not exist`, }); return; } try { await addUserToRole(projectId, role.id, user.id); refetchProjectAccess(); setUser(undefined); setOptions([]); setToastData({ type: 'success', title: 'Added user to project', text: `User added to the project with the role of ${role.name}`, }); } catch (e: any) { let error; if ( e .toString() .includes(`User already has access to project=${projectId}`) ) { error = `User already has access to project ${projectId}`; } else { error = e.toString() || 'Server problems when adding users.'; } setToastData({ type: 'error', title: error, }); } }; const getOptionLabel = (option: IProjectAccessUser | string) => { if (option && typeof option !== 'string') { return `${option.name || option.username || '(Empty name)'} <${ option.email || option.username }>`; } else return ''; }; return ( <> handleBlur()} value={user || ''} freeSolo isOptionEqualToValue={() => true} filterOptions={o => o} getOptionLabel={getOptionLabel} options={options} loading={loading} renderInput={params => ( ), endAdornment: ( <> } /> {params.InputProps.endAdornment} ), }} /> )} /> ); };