feat: redesign project invite popup
This commit is contained in:
@ -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}
|
||||
|
@ -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}) {
|
||||
|
@ -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;
|
25
frontend/src/shared/graphql/project/inviteProjectMembers.ts
Normal file
25
frontend/src/shared/graphql/project/inviteProjectMembers.ts
Normal 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;
|
Reference in New Issue
Block a user