Relation picker module (#335)

- Created a relation picker module
- Added a CustomeEntityForSelect type
This commit is contained in:
Lucas Bordeau
2023-06-20 11:06:53 +02:00
committed by GitHub
parent c120903a45
commit e2eb40c1ea
9 changed files with 64 additions and 50 deletions

View File

@ -14,7 +14,7 @@ import { IconArrowUpRight } from '@tabler/icons-react';
import { CommentThreadForDrawer } from '@/comments/types/CommentThreadForDrawer'; import { CommentThreadForDrawer } from '@/comments/types/CommentThreadForDrawer';
import CompanyChip from '@/companies/components/CompanyChip'; import CompanyChip from '@/companies/components/CompanyChip';
import { PersonChip } from '@/people/components/PersonChip'; import { PersonChip } from '@/people/components/PersonChip';
import { useFilteredSearchEntityQuery } from '@/ui/hooks/menu/useFilteredSearchEntityQuery'; import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef'; import { useListenClickOutsideArrayOfRef } from '@/ui/hooks/useListenClickOutsideArrayOfRef';
import { flatMapAndSortEntityForSelectArrayOfArrayByName } from '@/ui/utils/flatMapAndSortEntityForSelectArrayByName'; import { flatMapAndSortEntityForSelectArrayOfArrayByName } from '@/ui/utils/flatMapAndSortEntityForSelectArrayByName';
import { getLogoUrlFromDomainName } from '@/utils/utils'; import { getLogoUrlFromDomainName } from '@/utils/utils';
@ -24,9 +24,9 @@ import {
useSearchPeopleQuery, useSearchPeopleQuery,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { MultipleEntitySelect } from '../../relation-picker/components/MultipleEntitySelect';
import { useHandleCheckableCommentThreadTargetChange } from '../hooks/useHandleCheckableCommentThreadTargetChange'; import { useHandleCheckableCommentThreadTargetChange } from '../hooks/useHandleCheckableCommentThreadTargetChange';
import { CommentableEntityForSelect } from '../types/CommentableEntityForSelect';
import { MultipleEntitySelect } from './MultipleEntitySelect';
type OwnProps = { type OwnProps = {
commentThread: CommentThreadForDrawer; commentThread: CommentThreadForDrawer;
@ -112,12 +112,13 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
searchOnFields: ['firstname', 'lastname'], searchOnFields: ['firstname', 'lastname'],
orderByField: 'lastname', orderByField: 'lastname',
selectedIds: peopleIds, selectedIds: peopleIds,
mappingFunction: (entity) => ({ mappingFunction: (entity) =>
id: entity.id, ({
entityType: CommentableType.Person, id: entity.id,
name: `${entity.firstname} ${entity.lastname}`, entityType: CommentableType.Person,
avatarType: 'rounded', name: `${entity.firstname} ${entity.lastname}`,
}), avatarType: 'rounded',
} as CommentableEntityForSelect),
searchFilter, searchFilter,
}); });
@ -126,13 +127,14 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
searchOnFields: ['name'], searchOnFields: ['name'],
orderByField: 'name', orderByField: 'name',
selectedIds: companyIds, selectedIds: companyIds,
mappingFunction: (company) => ({ mappingFunction: (company) =>
id: company.id, ({
entityType: CommentableType.Company, id: company.id,
name: company.name, entityType: CommentableType.Company,
avatarUrl: getLogoUrlFromDomainName(company.domainName), name: company.name,
avatarType: 'squared', avatarUrl: getLogoUrlFromDomainName(company.domainName),
}), avatarType: 'squared',
} as CommentableEntityForSelect),
searchFilter, searchFilter,
}); });

View File

@ -8,8 +8,8 @@ import {
useRemoveCommentThreadTargetOnCommentThreadMutation, useRemoveCommentThreadTargetOnCommentThreadMutation,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { EntityForSelect } from '../components/MultipleEntitySelect';
import { GET_COMMENT_THREADS_BY_TARGETS } from '../services'; import { GET_COMMENT_THREADS_BY_TARGETS } from '../services';
import { CommentableEntityForSelect } from '../types/CommentableEntityForSelect';
import { CommentThreadForDrawer } from '../types/CommentThreadForDrawer'; import { CommentThreadForDrawer } from '../types/CommentThreadForDrawer';
export function useHandleCheckableCommentThreadTargetChange({ export function useHandleCheckableCommentThreadTargetChange({
@ -37,7 +37,7 @@ export function useHandleCheckableCommentThreadTargetChange({
return function handleCheckItemChange( return function handleCheckItemChange(
newCheckedValue: boolean, newCheckedValue: boolean,
entity: EntityForSelect, entity: CommentableEntityForSelect,
) { ) {
if (newCheckedValue) { if (newCheckedValue) {
addCommentThreadTargetOnCommentThread({ addCommentThreadTargetOnCommentThread({

View File

@ -1,6 +1,6 @@
import { CommentableType } from '~/generated/graphql'; import { CommentableType } from '~/generated/graphql';
export type CommentableEntity = { export type CommentableEntity = {
type: CommentableType;
id: string; id: string;
type: CommentableType;
}; };

View File

@ -0,0 +1,6 @@
import { EntityForSelect } from '@/relation-picker/types/EntityForSelect';
import { CommentableType } from '~/generated/graphql';
export type CommentableEntityForSelect = EntityForSelect & {
entityType: CommentableType;
};

View File

@ -1,42 +1,36 @@
import { debounce } from 'lodash'; import { debounce } from 'lodash';
import { EntityForSelect } from '@/relation-picker/types/EntityForSelect';
import { DropdownMenu } from '@/ui/components/menu/DropdownMenu'; import { DropdownMenu } from '@/ui/components/menu/DropdownMenu';
import { DropdownMenuCheckableItem } from '@/ui/components/menu/DropdownMenuCheckableItem'; import { DropdownMenuCheckableItem } from '@/ui/components/menu/DropdownMenuCheckableItem';
import { DropdownMenuItem } from '@/ui/components/menu/DropdownMenuItem'; import { DropdownMenuItem } from '@/ui/components/menu/DropdownMenuItem';
import { DropdownMenuItemContainer } from '@/ui/components/menu/DropdownMenuItemContainer'; import { DropdownMenuItemContainer } from '@/ui/components/menu/DropdownMenuItemContainer';
import { DropdownMenuSearch } from '@/ui/components/menu/DropdownMenuSearch'; import { DropdownMenuSearch } from '@/ui/components/menu/DropdownMenuSearch';
import { DropdownMenuSeparator } from '@/ui/components/menu/DropdownMenuSeparator'; import { DropdownMenuSeparator } from '@/ui/components/menu/DropdownMenuSeparator';
import { Avatar, AvatarType } from '@/users/components/Avatar'; import { Avatar } from '@/users/components/Avatar';
import { CommentableType } from '~/generated/graphql';
export type EntitiesForMultipleEntitySelect = { export type EntitiesForMultipleEntitySelect<
selectedEntities: EntityForSelect[]; CustomEntityForSelect extends EntityForSelect,
filteredSelectedEntities: EntityForSelect[]; > = {
entitiesToSelect: EntityForSelect[]; selectedEntities: CustomEntityForSelect[];
filteredSelectedEntities: CustomEntityForSelect[];
entitiesToSelect: CustomEntityForSelect[];
}; };
export type EntityTypeForSelect = CommentableType; // TODO: derivate from all usable entity types export function MultipleEntitySelect<
CustomEntityForSelect extends EntityForSelect,
export type EntityForSelect = { >({
id: string;
entityType: EntityTypeForSelect;
name: string;
avatarUrl?: string;
avatarType?: AvatarType;
};
export function MultipleEntitySelect({
entities, entities,
onItemCheckChange, onItemCheckChange,
onSearchFilterChange, onSearchFilterChange,
searchFilter, searchFilter,
}: { }: {
entities: EntitiesForMultipleEntitySelect; entities: EntitiesForMultipleEntitySelect<CustomEntityForSelect>;
searchFilter: string; searchFilter: string;
onSearchFilterChange: (newSearchFilter: string) => void; onSearchFilterChange: (newSearchFilter: string) => void;
onItemCheckChange: ( onItemCheckChange: (
newCheckedValue: boolean, newCheckedValue: boolean,
entity: EntityForSelect, entity: CustomEntityForSelect,
) => void; ) => void;
}) { }) {
const debouncedSetSearchFilter = debounce(onSearchFilterChange, 100, { const debouncedSetSearchFilter = debounce(onSearchFilterChange, 100, {

View File

@ -1,9 +1,7 @@
import * as Apollo from '@apollo/client'; import * as Apollo from '@apollo/client';
import { import { EntitiesForMultipleEntitySelect } from '@/relation-picker/components/MultipleEntitySelect';
EntitiesForMultipleEntitySelect, import { EntityForSelect } from '@/relation-picker/types/EntityForSelect';
EntityForSelect,
} from '@/comments/components/MultipleEntitySelect';
import { import {
Exact, Exact,
InputMaybe, InputMaybe,
@ -46,6 +44,7 @@ export function useFilteredSearchEntityQuery<
Array<EntityOrderByWithRelationInput> | EntityOrderByWithRelationInput Array<EntityOrderByWithRelationInput> | EntityOrderByWithRelationInput
>; >;
}>, }>,
CustomEntityForSelect extends EntityForSelect,
>({ >({
queryHook, queryHook,
searchOnFields, searchOnFields,
@ -66,10 +65,10 @@ export function useFilteredSearchEntityQuery<
orderByField: OrderByField; orderByField: OrderByField;
sortOrder?: SortOrder; sortOrder?: SortOrder;
selectedIds: string[]; selectedIds: string[];
mappingFunction: (entity: EntityType) => EntityForSelect; mappingFunction: (entity: EntityType) => CustomEntityForSelect;
limit?: number; limit?: number;
searchFilter: string; searchFilter: string;
}): EntitiesForMultipleEntitySelect { }): EntitiesForMultipleEntitySelect<CustomEntityForSelect> {
const { data: selectedEntitiesData } = queryHook({ const { data: selectedEntitiesData } = queryHook({
variables: { variables: {
where: { where: {

View File

@ -0,0 +1,11 @@
import { AvatarType } from '@/users/components/Avatar';
import { EntityTypeForSelect } from './EntityTypeForSelect';
export type EntityForSelect = {
id: string;
entityType: EntityTypeForSelect;
name: string;
avatarUrl?: string;
avatarType?: AvatarType;
};

View File

@ -0,0 +1,3 @@
import { CommentableType, PipelineProgressableType } from '~/generated/graphql';
export type EntityTypeForSelect = CommentableType | PipelineProgressableType;

View File

@ -1,10 +1,9 @@
import { EntityForSelect } from '@/comments/components/MultipleEntitySelect'; import { EntityForSelect } from '@/relation-picker/types/EntityForSelect';
export function flatMapAndSortEntityForSelectArrayOfArrayByName( export function flatMapAndSortEntityForSelectArrayOfArrayByName<
entityForSelectArray: EntityForSelect[][], T extends EntityForSelect,
) { >(entityForSelectArray: T[][]) {
const sortByName = (a: EntityForSelect, b: EntityForSelect) => const sortByName = (a: T, b: T) => a.name.localeCompare(b.name);
a.name.localeCompare(b.name);
return entityForSelectArray.flatMap((entity) => entity).sort(sortByName); return entityForSelectArray.flatMap((entity) => entity).sort(sortByName);
} }