1
0
mirror of https://github.com/Unleash/unleash.git synced 2025-04-19 01:17:18 +02:00
unleash.unleash/frontend/src/component/project/ProjectAccess/ProjectAccessAddUser/ProjectAccessAddUser.tsx
olav b21ae4164d refactor: remove outdated root role info text (#1112)
* refactor: remove unused imports

* refactor: remove outdated root role info text
2022-06-22 14:58:05 +02:00

228 lines
7.9 KiB
TypeScript

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<IProjectAccessUser | undefined>();
const [role, setRole] = useState<IProjectRole | undefined>();
const [options, setOptions] = useState<IProjectAccessUser[]>([]);
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 (
<>
<Grid container spacing={3} alignItems="flex-end">
<Grid item>
<Autocomplete
id="add-user-component"
style={{ width: 300 }}
noOptionsText="No users found."
onChange={handleSelectUser}
onBlur={() => handleBlur()}
value={user || ''}
freeSolo
isOptionEqualToValue={() => true}
filterOptions={o => o}
getOptionLabel={getOptionLabel}
options={options}
loading={loading}
renderInput={params => (
<TextField
{...params}
label="User"
variant="outlined"
size="small"
name="search"
onChange={handleQueryUpdate}
InputProps={{
...params.InputProps,
startAdornment: (
<InputAdornment position="start">
<Search />
</InputAdornment>
),
endAdornment: (
<>
<ConditionallyRender
condition={loading}
show={
<CircularProgress
color="inherit"
size={20}
/>
}
/>
{params.InputProps.endAdornment}
</>
),
}}
/>
)}
/>
</Grid>
<Grid item>
<ProjectRoleSelect
labelId="add-user-select-role-label"
id="add-user-select-role"
placeholder="Project role"
value={role?.id || -1}
onChange={handleRoleChange}
roles={roles}
/>
</Grid>
<Grid item>
<Button
variant="contained"
color="primary"
disabled={!user}
onClick={handleSubmit}
>
Add user
</Button>
</Grid>
</Grid>
</>
);
};