249 lines
6.7 KiB
TypeScript
249 lines
6.7 KiB
TypeScript
import React, { useEffect } from 'react';
|
|
import Admin from 'shared/components/Admin';
|
|
import Select from 'shared/components/Select';
|
|
import GlobalTopNavbar from 'App/TopNavbar';
|
|
import {
|
|
useUsersQuery,
|
|
useDeleteUserAccountMutation,
|
|
useCreateUserAccountMutation,
|
|
UsersDocument,
|
|
UsersQuery,
|
|
} from 'shared/generated/graphql';
|
|
import Input from 'shared/components/Input';
|
|
import styled from 'styled-components';
|
|
import Button from 'shared/components/Button';
|
|
import { useForm, Controller } from 'react-hook-form';
|
|
import { usePopup, Popup } from 'shared/components/PopupMenu';
|
|
import produce from 'immer';
|
|
import updateApolloCache from 'shared/utils/cache';
|
|
import { useCurrentUser } from 'App/context';
|
|
import { Redirect } from 'react-router';
|
|
import NOOP from 'shared/utils/noop';
|
|
|
|
const DeleteUserWrapper = styled.div`
|
|
display: flex;
|
|
flex-direction: column;
|
|
`;
|
|
|
|
const DeleteUserDescription = styled.p`
|
|
font-size: 14px;
|
|
`;
|
|
|
|
const DeleteUserButton = styled(Button)`
|
|
margin-top: 6px;
|
|
padding: 6px 12px;
|
|
width: 100%;
|
|
`;
|
|
|
|
type DeleteUserPopupProps = {
|
|
onDeleteUser: () => void;
|
|
};
|
|
|
|
const DeleteUserPopup: React.FC<DeleteUserPopupProps> = ({ onDeleteUser }) => {
|
|
return (
|
|
<DeleteUserWrapper>
|
|
<DeleteUserDescription>Deleting this user will remove all user related data.</DeleteUserDescription>
|
|
<DeleteUserButton onClick={() => onDeleteUser()} color="danger">
|
|
Delete user
|
|
</DeleteUserButton>
|
|
</DeleteUserWrapper>
|
|
);
|
|
};
|
|
|
|
type RoleCodeOption = {
|
|
label: string;
|
|
value: string;
|
|
};
|
|
|
|
type CreateUserData = {
|
|
email: string;
|
|
username: string;
|
|
fullName: string;
|
|
initials: string;
|
|
password: string;
|
|
roleCode: RoleCodeOption;
|
|
};
|
|
|
|
const CreateUserForm = styled.form`
|
|
display: flex;
|
|
flex-direction: column;
|
|
margin: 0 12px;
|
|
`;
|
|
|
|
const CreateUserButton = styled(Button)`
|
|
margin-top: 8px;
|
|
padding: 6px 12px;
|
|
width: 100%;
|
|
`;
|
|
|
|
const AddUserInput = styled(Input)`
|
|
margin-bottom: 8px;
|
|
`;
|
|
|
|
const InputError = styled.span`
|
|
color: rgba(${props => props.theme.colors.danger});
|
|
font-size: 12px;
|
|
`;
|
|
|
|
type AddUserPopupProps = {
|
|
onAddUser: (user: CreateUserData) => void;
|
|
};
|
|
|
|
const AddUserPopup: React.FC<AddUserPopupProps> = ({ onAddUser }) => {
|
|
const { register, handleSubmit, errors, control } = useForm<CreateUserData>();
|
|
|
|
const createUser = (data: CreateUserData) => {
|
|
onAddUser(data);
|
|
};
|
|
return (
|
|
<CreateUserForm onSubmit={handleSubmit(createUser)}>
|
|
<AddUserInput
|
|
floatingLabel
|
|
width="100%"
|
|
label="Full Name"
|
|
id="fullName"
|
|
name="fullName"
|
|
variant="alternate"
|
|
ref={register({ required: 'Full name is required' })}
|
|
/>
|
|
{errors.fullName && <InputError>{errors.fullName.message}</InputError>}
|
|
<AddUserInput
|
|
floatingLabel
|
|
width="100%"
|
|
label="Email"
|
|
id="email"
|
|
name="email"
|
|
variant="alternate"
|
|
ref={register({ required: 'Email is required' })}
|
|
/>
|
|
<Controller
|
|
control={control}
|
|
name="roleCode"
|
|
rules={{ required: 'Role is required' }}
|
|
render={({ onChange, value }) => (
|
|
<Select
|
|
label="Role"
|
|
value={value}
|
|
onChange={onChange}
|
|
options={[
|
|
{ label: 'Admin', value: 'admin' },
|
|
{ label: 'Member', value: 'member' },
|
|
]}
|
|
/>
|
|
)}
|
|
/>
|
|
{errors.roleCode && errors.roleCode.value && <InputError>{errors.roleCode.value.message}</InputError>}
|
|
<AddUserInput
|
|
floatingLabel
|
|
width="100%"
|
|
label="Username"
|
|
id="username"
|
|
name="username"
|
|
variant="alternate"
|
|
ref={register({ required: 'Username is required' })}
|
|
/>
|
|
{errors.username && <InputError>{errors.username.message}</InputError>}
|
|
<AddUserInput
|
|
floatingLabel
|
|
width="100%"
|
|
label="Initials"
|
|
id="initials"
|
|
name="initials"
|
|
variant="alternate"
|
|
ref={register({ required: 'Initials is required' })}
|
|
/>
|
|
{errors.initials && <InputError>{errors.initials.message}</InputError>}
|
|
<AddUserInput
|
|
floatingLabel
|
|
width="100%"
|
|
label="Password"
|
|
id="password"
|
|
name="password"
|
|
variant="alternate"
|
|
type="password"
|
|
ref={register({ required: 'Password is required' })}
|
|
/>
|
|
{errors.password && <InputError>{errors.password.message}</InputError>}
|
|
<CreateUserButton type="submit">Create</CreateUserButton>
|
|
</CreateUserForm>
|
|
);
|
|
};
|
|
|
|
const AdminRoute = () => {
|
|
useEffect(() => {
|
|
document.title = 'Taskcafé | Admin';
|
|
}, []);
|
|
const { loading, data } = useUsersQuery();
|
|
const { showPopup, hidePopup } = usePopup();
|
|
const { user } = useCurrentUser();
|
|
const [deleteUser] = useDeleteUserAccountMutation({
|
|
update: (client, response) => {
|
|
updateApolloCache<UsersQuery>(client, UsersDocument, cache =>
|
|
produce(cache, draftCache => {
|
|
draftCache.users = cache.users.filter(u => u.id !== response.data.deleteUserAccount.userAccount.id);
|
|
}),
|
|
);
|
|
},
|
|
});
|
|
const [createUser] = useCreateUserAccountMutation({
|
|
update: (client, createData) => {
|
|
const cacheData: any = client.readQuery({
|
|
query: UsersDocument,
|
|
});
|
|
const newData = produce(cacheData, (draftState: any) => {
|
|
draftState.users = [...draftState.users, { ...createData.data.createUserAccount }];
|
|
});
|
|
|
|
client.writeQuery({
|
|
query: UsersDocument,
|
|
data: {
|
|
...newData,
|
|
},
|
|
});
|
|
},
|
|
});
|
|
if (loading) {
|
|
return <GlobalTopNavbar projectID={null} onSaveProjectName={NOOP} name={null} />;
|
|
}
|
|
if (data && user) {
|
|
if (user.roles.org !== 'admin') {
|
|
return <Redirect to="/" />;
|
|
}
|
|
return (
|
|
<>
|
|
<GlobalTopNavbar projectID={null} onSaveProjectName={NOOP} name={null} />
|
|
<Admin
|
|
initialTab={0}
|
|
users={data.users}
|
|
canInviteUser={user.roles.org === 'admin'}
|
|
onInviteUser={NOOP}
|
|
onUpdateUserPassword={() => {
|
|
hidePopup();
|
|
}}
|
|
onDeleteUser={(userID, newOwnerID) => {
|
|
deleteUser({ variables: { userID, newOwnerID } });
|
|
hidePopup();
|
|
}}
|
|
onAddUser={$target => {
|
|
showPopup(
|
|
$target,
|
|
<Popup tab={0} title="Add member" onClose={() => hidePopup()}>
|
|
<AddUserPopup
|
|
onAddUser={u => {
|
|
const { roleCode, ...userData } = u;
|
|
createUser({ variables: { ...userData, roleCode: roleCode.value } });
|
|
hidePopup();
|
|
}}
|
|
/>
|
|
</Popup>,
|
|
);
|
|
}}
|
|
/>
|
|
</>
|
|
);
|
|
}
|
|
return <span>error</span>;
|
|
};
|
|
|
|
export default AdminRoute;
|