Feat/account owner picker (#359)

* Added account owner picker

* Regenerated graphql files

* Fixed pickers staying in edit mode with a new generic hook

* Fixed lint
This commit is contained in:
Lucas Bordeau
2023-06-22 19:47:04 +02:00
committed by GitHub
parent cd70209502
commit 4a2797c491
8 changed files with 147 additions and 66 deletions

View File

@ -1359,16 +1359,6 @@ export type User = {
workspaceMember?: Maybe<WorkspaceMember>;
};
export type UserCompaniesArgs = {
cursor?: InputMaybe<CompanyWhereUniqueInput>;
distinct?: InputMaybe<Array<CompanyScalarFieldEnum>>;
orderBy?: InputMaybe<Array<CompanyOrderByWithRelationInput>>;
skip?: InputMaybe<Scalars['Int']>;
take?: InputMaybe<Scalars['Int']>;
where?: InputMaybe<CompanyWhereInput>;
};
export type UserCreateNestedOneWithoutCommentsInput = {
connect?: InputMaybe<UserWhereUniqueInput>;
};
@ -1527,6 +1517,7 @@ export type WorkspaceMember = {
user: User;
userId: Scalars['String'];
workspace: Workspace;
workspaceId: Scalars['String'];
};
export type CreateCommentMutationVariables = Exact<{
@ -1706,6 +1697,7 @@ export type SearchPeopleQuery = { __typename?: 'Query', searchResults: Array<{ _
export type SearchUserQueryVariables = Exact<{
where?: InputMaybe<UserWhereInput>;
limit?: InputMaybe<Scalars['Int']>;
orderBy?: InputMaybe<Array<UserOrderByWithRelationInput> | UserOrderByWithRelationInput>;
}>;
@ -2575,8 +2567,8 @@ export type SearchPeopleQueryHookResult = ReturnType<typeof useSearchPeopleQuery
export type SearchPeopleLazyQueryHookResult = ReturnType<typeof useSearchPeopleLazyQuery>;
export type SearchPeopleQueryResult = Apollo.QueryResult<SearchPeopleQuery, SearchPeopleQueryVariables>;
export const SearchUserDocument = gql`
query SearchUser($where: UserWhereInput, $limit: Int) {
searchResults: findManyUser(where: $where, take: $limit) {
query SearchUser($where: UserWhereInput, $limit: Int, $orderBy: [UserOrderByWithRelationInput!]) {
searchResults: findManyUser(where: $where, take: $limit, orderBy: $orderBy) {
id
email
displayName
@ -2598,6 +2590,7 @@ export const SearchUserDocument = gql`
* variables: {
* where: // value for 'where'
* limit: // value for 'limit'
* orderBy: // value for 'orderBy'
* },
* });
*/

View File

@ -0,0 +1,26 @@
import { PersonChip } from '@/people/components/PersonChip';
import { EditableCellV2 } from '@/ui/components/editable-cell/EditableCellV2';
import { Company, User } from '~/generated/graphql';
import { CompanyAccountOwnerPicker } from './CompanyAccountOwnerPicker';
export type OwnProps = {
company: Pick<Company, 'id'> & {
accountOwner?: Pick<User, 'id' | 'displayName'> | null;
};
};
export function CompanyAccountOwnerCell({ company }: OwnProps) {
return (
<EditableCellV2
editModeContent={<CompanyAccountOwnerPicker company={company} />}
nonEditModeContent={
company.accountOwner?.displayName ? (
<PersonChip name={company.accountOwner?.displayName ?? ''} />
) : (
<></>
)
}
/>
);
}

View File

@ -0,0 +1,67 @@
import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect';
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState';
import { EntityForSelect } from '@/relation-picker/types/EntityForSelect';
import { Entity } from '@/relation-picker/types/EntityTypeForSelect';
import { useCloseEditableCell } from '@/ui/components/editable-cell/hooks/useCloseEditableCell';
import { useRecoilScopedState } from '@/ui/hooks/useRecoilScopedState';
import {
Company,
User,
useSearchUserQuery,
useUpdateCompanyMutation,
} from '~/generated/graphql';
export type OwnProps = {
company: Pick<Company, 'id'> & {
accountOwner?: Pick<User, 'id' | 'displayName'> | null;
};
};
type UserForSelect = EntityForSelect & {
entityType: Entity.User;
};
export function CompanyAccountOwnerPicker({ company }: OwnProps) {
const [searchFilter] = useRecoilScopedState(
relationPickerSearchFilterScopedState,
);
const [updateCompany] = useUpdateCompanyMutation();
const closeEditableCell = useCloseEditableCell();
const companies = useFilteredSearchEntityQuery({
queryHook: useSearchUserQuery,
selectedIds: [company?.accountOwner?.id ?? ''],
searchFilter: searchFilter,
mappingFunction: (user) => ({
entityType: Entity.User,
id: user.id,
name: user.displayName,
avatarType: 'rounded',
}),
orderByField: 'displayName',
searchOnFields: ['displayName'],
});
async function handleEntitySelected(selectedUser: UserForSelect) {
await updateCompany({
variables: {
...company,
accountOwnerId: selectedUser.id,
},
});
closeEditableCell();
}
return (
<SingleEntitySelect
onEntitySelected={handleEntitySelected}
entities={{
entitiesToSelect: companies.entitiesToSelect,
selectedEntity: companies.selectedEntities[0],
}}
/>
);
}

View File

@ -1,11 +1,9 @@
import { useRecoilState } from 'recoil';
import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect';
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState';
import { useCloseEditableCell } from '@/ui/components/editable-cell/hooks/useCloseEditableCell';
import { isCreateModeScopedState } from '@/ui/components/editable-cell/states/isCreateModeScopedState';
import { useRecoilScopedState } from '@/ui/hooks/useRecoilScopedState';
import { isSomeInputInEditModeState } from '@/ui/tables/states/isSomeInputInEditModeState';
import { getLogoUrlFromDomainName } from '@/utils/utils';
import {
CommentableType,
@ -26,9 +24,8 @@ export function PeopleCompanyPicker({ people }: OwnProps) {
relationPickerSearchFilterScopedState,
);
const [updatePeople] = useUpdatePeopleMutation();
const [, setIsSomeInputInEditMode] = useRecoilState(
isSomeInputInEditModeState,
);
const closeEditableCell = useCloseEditableCell();
const companies = useFilteredSearchEntityQuery({
queryHook: useSearchCompanyQuery,
@ -46,14 +43,14 @@ export function PeopleCompanyPicker({ people }: OwnProps) {
});
async function handleEntitySelected(entity: any) {
setIsSomeInputInEditMode(false);
await updatePeople({
variables: {
...people,
companyId: entity.id,
},
});
closeEditableCell();
}
function handleCreate() {

View File

@ -1,3 +1,12 @@
import { CommentableType, PipelineProgressableType } from '~/generated/graphql';
export type EntityTypeForSelect = CommentableType | PipelineProgressableType;
export enum Entity {
Company = 'Company',
Person = 'Person',
User = 'User',
}
export type EntityTypeForSelect =
| CommentableType
| PipelineProgressableType
| Entity;

View File

@ -28,8 +28,16 @@ export const SEARCH_PEOPLE_QUERY = gql`
`;
export const SEARCH_USER_QUERY = gql`
query SearchUser($where: UserWhereInput, $limit: Int) {
searchResults: findManyUser(where: $where, take: $limit) {
query SearchUser(
$where: UserWhereInput
$limit: Int
$orderBy: [UserOrderByWithRelationInput!]
) {
searchResults: findManyUser(
where: $where
take: $limit
orderBy: $orderBy
) {
id
email
displayName

View File

@ -0,0 +1,19 @@
import { useCallback } from 'react';
import { useRecoilState } from 'recoil';
import { useRecoilScopedState } from '@/ui/hooks/useRecoilScopedState';
import { isSomeInputInEditModeState } from '@/ui/tables/states/isSomeInputInEditModeState';
import { isEditModeScopedState } from '../states/isEditModeScopedState';
export function useCloseEditableCell() {
const [, setIsSomeInputInEditMode] = useRecoilState(
isSomeInputInEditModeState,
);
const [, setIsEditMode] = useRecoilScopedState(isEditModeScopedState);
return useCallback(() => {
setIsSomeInputInEditMode(false);
setIsEditMode(false);
}, [setIsEditMode, setIsSomeInputInEditMode]);
}

View File

@ -1,17 +1,12 @@
import { useMemo } from 'react';
import { createColumnHelper } from '@tanstack/react-table';
import { CompanyAccountOwnerCell } from '@/companies/components/CompanyAccountOwnerCell';
import { CompanyEditableNameChipCell } from '@/companies/components/CompanyEditableNameCell';
import {
PersonChip,
PersonChipPropsType,
} from '@/people/components/PersonChip';
import { SearchConfigType } from '@/search/interfaces/interface';
import { SEARCH_USER_QUERY } from '@/search/services/search';
import { EditableDate } from '@/ui/components/editable-cell/types/EditableDate';
import { EditableRelation } from '@/ui/components/editable-cell/types/EditableRelation';
import { EditableText } from '@/ui/components/editable-cell/types/EditableText';
import { ColumnHead } from '@/ui/components/table/ColumnHead';
import { RecoilScope } from '@/ui/hooks/RecoilScope';
import {
IconBuildingSkyscraper,
IconCalendarEvent,
@ -23,7 +18,6 @@ import {
import { getCheckBoxColumn } from '@/ui/tables/utils/getCheckBoxColumn';
import {
GetCompaniesQuery,
QueryMode,
useUpdateCompanyMutation,
} from '~/generated/graphql';
@ -149,41 +143,9 @@ export const useCompaniesColumns = () => {
/>
),
cell: (props) => (
<EditableRelation<any, PersonChipPropsType>
relation={props.row.original.accountOwner}
searchPlaceholder="Account Owner"
ChipComponent={PersonChip}
chipComponentPropsMapper={(
accountOwner: any,
): PersonChipPropsType => {
return {
name: accountOwner.displayName || '',
};
}}
onChange={(relation: any) => {
updateCompany({
variables: {
...props.row.original,
accountOwnerId: relation.id,
},
});
}}
searchConfig={
{
query: SEARCH_USER_QUERY,
template: (searchInput: string) => ({
displayName: {
contains: `%${searchInput}%`,
mode: QueryMode.Insensitive,
},
}),
resultMapper: (accountOwner: any) => ({
render: (accountOwner: any) => accountOwner.displayName,
value: accountOwner,
}),
} satisfies SearchConfigType
}
/>
<RecoilScope>
<CompanyAccountOwnerCell company={props.row.original} />
</RecoilScope>
),
}),
];