feat: redesign project invite popup

This commit is contained in:
Jordan Knott
2020-10-14 16:52:32 -05:00
parent 737d2b640f
commit 262f9cbdda
18 changed files with 530 additions and 364 deletions

View File

@ -16,7 +16,7 @@ import {
} from 'react-router-dom';
import {
useUpdateProjectMemberRoleMutation,
useInviteProjectMemberMutation,
useInviteProjectMembersMutation,
useDeleteProjectMemberMutation,
useToggleTaskLabelMutation,
useUpdateProjectNameMutation,
@ -84,9 +84,10 @@ type InviteUserData = {
suerID?: string;
};
type UserManagementPopupProps = {
projectID: string;
users: Array<User>;
projectMembers: Array<TaskUser>;
onInviteProjectMember: (data: InviteUserData) => void;
onInviteProjectMembers: (data: Array<InviteUserData>) => void;
};
const VisibiltyPrivateIcon = styled(Lock)`
@ -131,14 +132,14 @@ type MemberFilterOptions = {
organization?: boolean;
};
const fetchMembers = async (client: any, options: MemberFilterOptions, input: string, cb: any) => {
const fetchMembers = async (client: any, projectID: string, options: MemberFilterOptions, input: string, cb: any) => {
if (input && input.trim().length < 3) {
return [];
}
const res = await client.query({
query: gql`
query {
searchMembers(input: {SearchFilter:"${input}"}) {
searchMembers(input: {SearchFilter:"${input}", projectID:"${projectID}"}) {
similarity
confirmed
joined
@ -165,7 +166,7 @@ const fetchMembers = async (client: any, options: MemberFilterOptions, input: st
emails.push(m.user.email);
return {
label: m.user.fullName,
value: { id: m.id, type: 0, profileIcon: m.user.profileIcon },
value: { id: m.user.id, type: 0, profileIcon: m.user.profileIcon },
};
}),
];
@ -214,6 +215,7 @@ const OptionContent = styled.div`
`;
const UserOption: React.FC<UserOptionProps> = ({ isDisabled, isFocused, innerProps, label, data }) => {
console.log(data);
return !isDisabled ? (
<OptionWrapper {...innerProps} isFocused={isFocused}>
<TaskAssignee
@ -280,16 +282,24 @@ const InviteContainer = styled.div`
flex-direction: column;
`;
const UserManagementPopup: React.FC<UserManagementPopupProps> = ({ users, projectMembers, onInviteProjectMember }) => {
const UserManagementPopup: React.FC<UserManagementPopupProps> = ({
projectID,
users,
projectMembers,
onInviteProjectMembers,
}) => {
const client = useApolloClient();
const [invitedUsers, setInvitedUsers] = useState<Array<any> | null>(null);
return (
<Popup tab={0} title="Invite a user">
<InviteContainer>
<AsyncSelect
getOptionValue={option => option.value.id}
placeholder="Email address or username"
noOptionsMessage={() => null}
onChange={(e: any) => setInvitedUsers(e ? e.value : null)}
onChange={(e: any) => {
setInvitedUsers(e);
}}
isMulti
autoFocus
cacheOptions
@ -301,13 +311,25 @@ const UserManagementPopup: React.FC<UserManagementPopupProps> = ({ users, projec
IndicatorSeparator: null,
DropdownIndicator: null,
}}
loadOptions={(i, cb) => fetchMembers(client, {}, i, cb)}
loadOptions={(i, cb) => fetchMembers(client, projectID, {}, i, cb)}
/>
</InviteContainer>
<InviteButton
onClick={() => {
// FUCK, gotta rewrite invite member to be MULTIPLE. SHIT!
// onInviteProjectMember();
if (invitedUsers) {
onInviteProjectMembers(
invitedUsers.map(user => {
if (user.value.type === 0) {
return {
userID: user.value.id,
};
}
return {
email: user.value.id,
};
}),
);
}
}}
disabled={invitedUsers === null}
hoverVariant="none"
@ -398,14 +420,17 @@ const Project = () => {
},
});
const [inviteProjectMember] = useInviteProjectMemberMutation({
const [inviteProjectMembers] = useInviteProjectMembersMutation({
update: (client, response) => {
updateApolloCache<FindProjectQuery>(
client,
FindProjectDocument,
cache =>
produce(cache, draftCache => {
draftCache.findProject.members.push({ ...response.data.inviteProjectMember.member });
draftCache.findProject.members = [
...cache.findProject.members,
...response.data.inviteProjectMembers.members,
];
}),
{ projectID },
);
@ -472,8 +497,10 @@ const Project = () => {
showPopup(
$target,
<UserManagementPopup
onInviteProjectMember={userID => {
// /inviteProjectMember({ variables: { userID, projectID } });
projectID={projectID}
onInviteProjectMembers={members => {
inviteProjectMembers({ variables: { projectID, members } });
hidePopup();
}}
users={data.users}
projectMembers={data.findProject.members}

View File

@ -289,7 +289,7 @@ export type Mutation = {
deleteTeamMember: DeleteTeamMemberPayload;
deleteUserAccount: DeleteUserAccountPayload;
duplicateTaskGroup: DuplicateTaskGroupPayload;
inviteProjectMember: InviteProjectMemberPayload;
inviteProjectMembers: InviteProjectMembersPayload;
logoutUser: Scalars['Boolean'];
removeTaskLabel: Task;
setTaskChecklistItemComplete: TaskChecklistItem;
@ -439,8 +439,8 @@ export type MutationDuplicateTaskGroupArgs = {
};
export type MutationInviteProjectMemberArgs = {
input: InviteProjectMember;
export type MutationInviteProjectMembersArgs = {
input: InviteProjectMembers;
};
@ -694,16 +694,21 @@ export type UpdateProjectLabelColor = {
labelColorID: Scalars['UUID'];
};
export type InviteProjectMember = {
projectID: Scalars['UUID'];
export type MemberInvite = {
userID?: Maybe<Scalars['UUID']>;
email?: Maybe<Scalars['String']>;
};
export type InviteProjectMemberPayload = {
__typename?: 'InviteProjectMemberPayload';
export type InviteProjectMembers = {
projectID: Scalars['UUID'];
members: Array<MemberInvite>;
};
export type InviteProjectMembersPayload = {
__typename?: 'InviteProjectMembersPayload';
ok: Scalars['Boolean'];
member: Member;
projectID: Scalars['UUID'];
members: Array<Member>;
};
export type DeleteProjectMember = {
@ -1446,19 +1451,18 @@ export type DeleteProjectMemberMutation = (
) }
);
export type InviteProjectMemberMutationVariables = {
export type InviteProjectMembersMutationVariables = {
projectID: Scalars['UUID'];
userID?: Maybe<Scalars['UUID']>;
email?: Maybe<Scalars['String']>;
members: Array<MemberInvite>;
};
export type InviteProjectMemberMutation = (
export type InviteProjectMembersMutation = (
{ __typename?: 'Mutation' }
& { inviteProjectMember: (
{ __typename?: 'InviteProjectMemberPayload' }
& Pick<InviteProjectMemberPayload, 'ok'>
& { member: (
& { inviteProjectMembers: (
{ __typename?: 'InviteProjectMembersPayload' }
& Pick<InviteProjectMembersPayload, 'ok'>
& { members: Array<(
{ __typename?: 'Member' }
& Pick<Member, 'id' | 'fullName' | 'username'>
& { profileIcon: (
@ -1468,7 +1472,7 @@ export type InviteProjectMemberMutation = (
{ __typename?: 'Role' }
& Pick<Role, 'code' | 'name'>
) }
) }
)> }
) }
);
@ -2978,11 +2982,11 @@ export function useDeleteProjectMemberMutation(baseOptions?: ApolloReactHooks.Mu
export type DeleteProjectMemberMutationHookResult = ReturnType<typeof useDeleteProjectMemberMutation>;
export type DeleteProjectMemberMutationResult = ApolloReactCommon.MutationResult<DeleteProjectMemberMutation>;
export type DeleteProjectMemberMutationOptions = ApolloReactCommon.BaseMutationOptions<DeleteProjectMemberMutation, DeleteProjectMemberMutationVariables>;
export const InviteProjectMemberDocument = gql`
mutation inviteProjectMember($projectID: UUID!, $userID: UUID, $email: String) {
inviteProjectMember(input: {projectID: $projectID, userID: $userID, email: $email}) {
export const InviteProjectMembersDocument = gql`
mutation inviteProjectMembers($projectID: UUID!, $members: [MemberInvite!]!) {
inviteProjectMembers(input: {projectID: $projectID, members: $members}) {
ok
member {
members {
id
fullName
profileIcon {
@ -2999,33 +3003,32 @@ export const InviteProjectMemberDocument = gql`
}
}
`;
export type InviteProjectMemberMutationFn = ApolloReactCommon.MutationFunction<InviteProjectMemberMutation, InviteProjectMemberMutationVariables>;
export type InviteProjectMembersMutationFn = ApolloReactCommon.MutationFunction<InviteProjectMembersMutation, InviteProjectMembersMutationVariables>;
/**
* __useInviteProjectMemberMutation__
* __useInviteProjectMembersMutation__
*
* To run a mutation, you first call `useInviteProjectMemberMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useInviteProjectMemberMutation` returns a tuple that includes:
* To run a mutation, you first call `useInviteProjectMembersMutation` within a React component and pass it any options that fit your needs.
* When your component renders, `useInviteProjectMembersMutation` returns a tuple that includes:
* - A mutate function that you can call at any time to execute the mutation
* - An object with fields that represent the current status of the mutation's execution
*
* @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2;
*
* @example
* const [inviteProjectMemberMutation, { data, loading, error }] = useInviteProjectMemberMutation({
* const [inviteProjectMembersMutation, { data, loading, error }] = useInviteProjectMembersMutation({
* variables: {
* projectID: // value for 'projectID'
* userID: // value for 'userID'
* email: // value for 'email'
* members: // value for 'members'
* },
* });
*/
export function useInviteProjectMemberMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<InviteProjectMemberMutation, InviteProjectMemberMutationVariables>) {
return ApolloReactHooks.useMutation<InviteProjectMemberMutation, InviteProjectMemberMutationVariables>(InviteProjectMemberDocument, baseOptions);
export function useInviteProjectMembersMutation(baseOptions?: ApolloReactHooks.MutationHookOptions<InviteProjectMembersMutation, InviteProjectMembersMutationVariables>) {
return ApolloReactHooks.useMutation<InviteProjectMembersMutation, InviteProjectMembersMutationVariables>(InviteProjectMembersDocument, baseOptions);
}
export type InviteProjectMemberMutationHookResult = ReturnType<typeof useInviteProjectMemberMutation>;
export type InviteProjectMemberMutationResult = ApolloReactCommon.MutationResult<InviteProjectMemberMutation>;
export type InviteProjectMemberMutationOptions = ApolloReactCommon.BaseMutationOptions<InviteProjectMemberMutation, InviteProjectMemberMutationVariables>;
export type InviteProjectMembersMutationHookResult = ReturnType<typeof useInviteProjectMembersMutation>;
export type InviteProjectMembersMutationResult = ApolloReactCommon.MutationResult<InviteProjectMembersMutation>;
export type InviteProjectMembersMutationOptions = ApolloReactCommon.BaseMutationOptions<InviteProjectMembersMutation, InviteProjectMembersMutationVariables>;
export const UpdateProjectMemberRoleDocument = gql`
mutation updateProjectMemberRole($projectID: UUID!, $userID: UUID!, $roleCode: RoleCode!) {
updateProjectMemberRole(input: {projectID: $projectID, userID: $userID, roleCode: $roleCode}) {

View File

@ -1,25 +0,0 @@
import gql from 'graphql-tag';
export const INVITE_PROJECT_MEMBER_MUTATION = gql`
mutation inviteProjectMember($projectID: UUID!, $userID: UUID, $email: String) {
inviteProjectMember(input: { projectID: $projectID, userID: $userID, email: $email }) {
ok
member {
id
fullName
profileIcon {
url
initials
bgColor
}
username
role {
code
name
}
}
}
}
`;
export default INVITE_PROJECT_MEMBER_MUTATION;

View File

@ -0,0 +1,25 @@
import gql from 'graphql-tag';
export const INVITE_PROJECT_MEMBERS_MUTATION = gql`
mutation inviteProjectMembers($projectID: UUID!, $members: [MemberInvite!]!) {
inviteProjectMembers(input: { projectID: $projectID, members: $members }) {
ok
members {
id
fullName
profileIcon {
url
initials
bgColor
}
username
role {
code
name
}
}
}
}
`;
export default INVITE_PROJECT_MEMBERS_MUTATION;