From 4a2797c491213f0cbc90e3dfbfbb5cbdc06df868 Mon Sep 17 00:00:00 2001 From: Lucas Bordeau Date: Thu, 22 Jun 2023 19:47:04 +0200 Subject: [PATCH] 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 --- front/src/generated/graphql.tsx | 17 ++--- .../components/CompanyAccountOwnerCell.tsx | 26 +++++++ .../components/CompanyAccountOwnerPicker.tsx | 67 +++++++++++++++++++ .../people/components/PeopleCompanyPicker.tsx | 13 ++-- .../types/EntityTypeForSelect.ts | 11 ++- front/src/modules/search/services/search.ts | 12 +++- .../hooks/useCloseEditableCell.ts | 19 ++++++ .../src/pages/companies/companies-columns.tsx | 48 ++----------- 8 files changed, 147 insertions(+), 66 deletions(-) create mode 100644 front/src/modules/companies/components/CompanyAccountOwnerCell.tsx create mode 100644 front/src/modules/companies/components/CompanyAccountOwnerPicker.tsx create mode 100644 front/src/modules/ui/components/editable-cell/hooks/useCloseEditableCell.ts diff --git a/front/src/generated/graphql.tsx b/front/src/generated/graphql.tsx index d1ad74693..74bd17043 100644 --- a/front/src/generated/graphql.tsx +++ b/front/src/generated/graphql.tsx @@ -1359,16 +1359,6 @@ export type User = { workspaceMember?: Maybe; }; - -export type UserCompaniesArgs = { - cursor?: InputMaybe; - distinct?: InputMaybe>; - orderBy?: InputMaybe>; - skip?: InputMaybe; - take?: InputMaybe; - where?: InputMaybe; -}; - export type UserCreateNestedOneWithoutCommentsInput = { connect?: InputMaybe; }; @@ -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; limit?: InputMaybe; + orderBy?: InputMaybe | UserOrderByWithRelationInput>; }>; @@ -2575,8 +2567,8 @@ export type SearchPeopleQueryHookResult = ReturnType; export type SearchPeopleQueryResult = Apollo.QueryResult; 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' * }, * }); */ diff --git a/front/src/modules/companies/components/CompanyAccountOwnerCell.tsx b/front/src/modules/companies/components/CompanyAccountOwnerCell.tsx new file mode 100644 index 000000000..f7026f75d --- /dev/null +++ b/front/src/modules/companies/components/CompanyAccountOwnerCell.tsx @@ -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 & { + accountOwner?: Pick | null; + }; +}; + +export function CompanyAccountOwnerCell({ company }: OwnProps) { + return ( + } + nonEditModeContent={ + company.accountOwner?.displayName ? ( + + ) : ( + <> + ) + } + /> + ); +} diff --git a/front/src/modules/companies/components/CompanyAccountOwnerPicker.tsx b/front/src/modules/companies/components/CompanyAccountOwnerPicker.tsx new file mode 100644 index 000000000..2def2eb66 --- /dev/null +++ b/front/src/modules/companies/components/CompanyAccountOwnerPicker.tsx @@ -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 & { + accountOwner?: Pick | 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 ( + + ); +} diff --git a/front/src/modules/people/components/PeopleCompanyPicker.tsx b/front/src/modules/people/components/PeopleCompanyPicker.tsx index 6334a1343..c46465424 100644 --- a/front/src/modules/people/components/PeopleCompanyPicker.tsx +++ b/front/src/modules/people/components/PeopleCompanyPicker.tsx @@ -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() { diff --git a/front/src/modules/relation-picker/types/EntityTypeForSelect.ts b/front/src/modules/relation-picker/types/EntityTypeForSelect.ts index 756c20e58..e27c21f6f 100644 --- a/front/src/modules/relation-picker/types/EntityTypeForSelect.ts +++ b/front/src/modules/relation-picker/types/EntityTypeForSelect.ts @@ -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; diff --git a/front/src/modules/search/services/search.ts b/front/src/modules/search/services/search.ts index 49ef510f3..e5d713901 100644 --- a/front/src/modules/search/services/search.ts +++ b/front/src/modules/search/services/search.ts @@ -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 diff --git a/front/src/modules/ui/components/editable-cell/hooks/useCloseEditableCell.ts b/front/src/modules/ui/components/editable-cell/hooks/useCloseEditableCell.ts new file mode 100644 index 000000000..4ac9d260d --- /dev/null +++ b/front/src/modules/ui/components/editable-cell/hooks/useCloseEditableCell.ts @@ -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]); +} diff --git a/front/src/pages/companies/companies-columns.tsx b/front/src/pages/companies/companies-columns.tsx index fad8da1cc..62b61b2bc 100644 --- a/front/src/pages/companies/companies-columns.tsx +++ b/front/src/pages/companies/companies-columns.tsx @@ -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) => ( - - 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 - } - /> + + + ), }), ];