Add search to cmd bar (#667)

* Move useFilteredSearchEntityQuery from relation picker to search module

* refactor duplicated code with useFilteredSearchCompanyQuery

* Implement similar pattern for people than for companies with useFilteredSearchEntityQuery

* Fix warning from a previous PR

* Enable search from menu

* Add companies to search

* Fix ESLint

* Refactor

* Fix according to peer review

---------

Co-authored-by: Charles Bochet <charles@twenty.com>
This commit is contained in:
Félix Malfait 2023-07-16 00:23:37 +02:00 committed by GitHub
parent b982788100
commit 7959308e0b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 202 additions and 139 deletions

View File

@ -1,6 +1,7 @@
import { useLocation } from 'react-router-dom'; import { useLocation } from 'react-router-dom';
import { useTheme } from '@emotion/react'; import { useTheme } from '@emotion/react';
import { useCommandMenu } from '@/command-menu/hooks/useCommandMenu';
import { SettingsNavbar } from '@/settings/components/SettingsNavbar'; import { SettingsNavbar } from '@/settings/components/SettingsNavbar';
import { import {
IconBuildingSkyscraper, IconBuildingSkyscraper,
@ -19,6 +20,7 @@ import NavTitle from './modules/ui/layout/navbar/NavTitle';
export function AppNavbar() { export function AppNavbar() {
const theme = useTheme(); const theme = useTheme();
const currentPath = useLocation().pathname; const currentPath = useLocation().pathname;
const { openCommandMenu } = useCommandMenu();
const isSubNavbarDisplayed = useIsSubNavbarDisplayed(); const isSubNavbarDisplayed = useIsSubNavbarDisplayed();
@ -29,9 +31,10 @@ export function AppNavbar() {
<> <>
<NavItem <NavItem
label="Search" label="Search"
to="/search"
icon={<IconSearch size={theme.icon.size.md} />} icon={<IconSearch size={theme.icon.size.md} />}
soon={true} onClick={() => {
openCommandMenu();
}}
/> />
<NavItem <NavItem
label="Inbox" label="Inbox"

View File

@ -1,10 +1,15 @@
import { useRecoilState } from 'recoil'; import { useState } from 'react';
import { useTheme } from '@emotion/react';
import { useRecoilValue } from 'recoil';
import { usePreviousHotkeyScope } from '@/lib/hotkeys/hooks/usePreviousHotkeyScope'; import { useFilteredSearchCompanyQuery } from '@/companies/services';
import { useScopedHotkeys } from '@/lib/hotkeys/hooks/useScopedHotkeys'; import { useScopedHotkeys } from '@/lib/hotkeys/hooks/useScopedHotkeys';
import { AppHotkeyScope } from '@/lib/hotkeys/types/AppHotkeyScope'; import { AppHotkeyScope } from '@/lib/hotkeys/types/AppHotkeyScope';
import { useFilteredSearchPeopleQuery } from '@/people/services';
import { Avatar } from '@/users/components/Avatar';
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpened'; import { useCommandMenu } from '../hooks/useCommandMenu';
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
import { CommandMenuItem } from './CommandMenuItem'; import { CommandMenuItem } from './CommandMenuItem';
import { import {
@ -16,31 +21,29 @@ import {
} from './CommandMenuStyles'; } from './CommandMenuStyles';
export function CommandMenu() { export function CommandMenu() {
const [open, setOpen] = useRecoilState(isCommandMenuOpenedState); const { openCommandMenu, closeCommandMenu } = useCommandMenu();
const isCommandMenuOpened = useRecoilValue(isCommandMenuOpenedState);
const [search, setSearch] = useState('');
useScopedHotkeys( useScopedHotkeys(
'ctrl+k,meta+k', 'ctrl+k,meta+k',
() => { () => {
handleOpenChange(!open); openCommandMenu();
}, },
AppHotkeyScope.CommandMenu, AppHotkeyScope.CommandMenu,
[setOpen, open, handleOpenChange], [openCommandMenu],
); );
const { const people = useFilteredSearchPeopleQuery({
setHotkeyScopeAndMemorizePreviousScope, searchFilter: search,
goBackToPreviousHotkeyScope, selectedIds: [],
} = usePreviousHotkeyScope(); limit: 3,
});
function handleOpenChange(newOpenState: boolean) { const companies = useFilteredSearchCompanyQuery({
if (newOpenState) { searchFilter: search,
setOpen(true); selectedIds: [],
setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenu); limit: 3,
} else { });
setOpen(false);
goBackToPreviousHotkeyScope();
}
}
/* /*
TODO: Allow performing actions on page through CommandBar TODO: Allow performing actions on page through CommandBar
@ -79,15 +82,64 @@ export function CommandMenu() {
</StyledGroup> </StyledGroup>
);*/ );*/
const theme = useTheme();
return ( return (
<StyledDialog <StyledDialog
open={open} open={isCommandMenuOpened}
onOpenChange={handleOpenChange} onOpenChange={(opened) => {
if (!opened) {
closeCommandMenu();
}
}}
label="Global Command Menu" label="Global Command Menu"
shouldFilter={false}
> >
<StyledInput placeholder="Search" /> <StyledInput
placeholder="Search"
value={search}
onValueChange={setSearch}
/>
<StyledList> <StyledList>
<StyledEmpty>No results found.</StyledEmpty> <StyledEmpty>No results found.</StyledEmpty>
{!!people.entitiesToSelect.length && (
<StyledGroup heading="People">
{people.entitiesToSelect.map((person) => (
<CommandMenuItem
to={`person/${person.id}`}
label={person.name}
key={person.id}
icon={
<Avatar
avatarUrl={person.avatarUrl}
size={theme.icon.size.sm}
colorId={person.id}
placeholder={person.name}
/>
}
/>
))}
</StyledGroup>
)}
{!!companies.entitiesToSelect.length && (
<StyledGroup heading="Companies">
{companies.entitiesToSelect.map((company) => (
<CommandMenuItem
to={`companies/${company.id}`}
label={company.name}
key={company.id}
icon={
<Avatar
avatarUrl={company.avatarUrl}
size={theme.icon.size.sm}
colorId={company.id}
placeholder={company.name}
/>
}
/>
))}
</StyledGroup>
)}
<StyledGroup heading="Navigate"> <StyledGroup heading="Navigate">
<CommandMenuItem <CommandMenuItem
to="/people" to="/people"

View File

@ -1,11 +1,10 @@
import React from 'react'; import React from 'react';
import { ReactNode } from 'react'; import { ReactNode } from 'react';
import { useNavigate } from 'react-router-dom'; import { useNavigate } from 'react-router-dom';
import { useSetRecoilState } from 'recoil';
import { IconArrowUpRight } from '@/ui/icons'; import { IconArrowUpRight } from '@/ui/icons';
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpened'; import { useCommandMenu } from '../hooks/useCommandMenu';
import { import {
StyledIconAndLabelContainer, StyledIconAndLabelContainer,
@ -30,15 +29,15 @@ export function CommandMenuItem({
icon, icon,
shortcuts, shortcuts,
}: OwnProps) { }: OwnProps) {
const setOpen = useSetRecoilState(isCommandMenuOpenedState);
const navigate = useNavigate(); const navigate = useNavigate();
const { closeCommandMenu } = useCommandMenu();
if (to) { if (to && !icon) {
icon = <IconArrowUpRight />; icon = <IconArrowUpRight />;
} }
const onItemClick = () => { const onItemClick = () => {
setOpen(false); closeCommandMenu();
if (onClick) { if (onClick) {
onClick(); onClick();

View File

@ -12,8 +12,8 @@ export const StyledDialog = styled(Command.Dialog)`
padding: 0; padding: 0;
padding: ${({ theme }) => theme.spacing(1)}; padding: ${({ theme }) => theme.spacing(1)};
position: fixed; position: fixed;
top: 50%; top: 30%;
transform: translate(-50%, -50%); transform: translateX(-50%);
width: 100%; width: 100%;
z-index: 1000; z-index: 1000;
`; `;

View File

@ -0,0 +1,31 @@
import { useRecoilState } from 'recoil';
import { usePreviousHotkeyScope } from '@/lib/hotkeys/hooks/usePreviousHotkeyScope';
import { AppHotkeyScope } from '@/lib/hotkeys/types/AppHotkeyScope';
import { isCommandMenuOpenedState } from '../states/isCommandMenuOpenedState';
export function useCommandMenu() {
const [, setIsCommandMenuOpenedState] = useRecoilState(
isCommandMenuOpenedState,
);
const {
setHotkeyScopeAndMemorizePreviousScope,
goBackToPreviousHotkeyScope,
} = usePreviousHotkeyScope();
function openCommandMenu() {
setIsCommandMenuOpenedState(true);
setHotkeyScopeAndMemorizePreviousScope(AppHotkeyScope.CommandMenu);
}
function closeCommandMenu() {
setIsCommandMenuOpenedState(false);
goBackToPreviousHotkeyScope();
}
return {
openCommandMenu,
closeCommandMenu,
};
}

View File

@ -9,24 +9,21 @@ import {
} from '@floating-ui/react'; } from '@floating-ui/react';
import { useHandleCheckableCommentThreadTargetChange } from '@/comments/hooks/useHandleCheckableCommentThreadTargetChange'; import { useHandleCheckableCommentThreadTargetChange } from '@/comments/hooks/useHandleCheckableCommentThreadTargetChange';
import { CommentableEntityForSelect } from '@/comments/types/CommentableEntityForSelect';
import { CompanyChip } from '@/companies/components/CompanyChip'; import { CompanyChip } from '@/companies/components/CompanyChip';
import { useFilteredSearchCompanyQuery } from '@/companies/services';
import { usePreviousHotkeyScope } from '@/lib/hotkeys/hooks/usePreviousHotkeyScope'; import { usePreviousHotkeyScope } from '@/lib/hotkeys/hooks/usePreviousHotkeyScope';
import { useScopedHotkeys } from '@/lib/hotkeys/hooks/useScopedHotkeys'; import { useScopedHotkeys } from '@/lib/hotkeys/hooks/useScopedHotkeys';
import { PersonChip } from '@/people/components/PersonChip'; import { PersonChip } from '@/people/components/PersonChip';
import { useFilteredSearchPeopleQuery } from '@/people/services';
import { RecoilScope } from '@/recoil-scope/components/RecoilScope'; import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
import { MultipleEntitySelect } from '@/relation-picker/components/MultipleEntitySelect'; import { MultipleEntitySelect } from '@/relation-picker/components/MultipleEntitySelect';
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
import { RelationPickerHotkeyScope } from '@/relation-picker/types/RelationPickerHotkeyScope'; import { RelationPickerHotkeyScope } from '@/relation-picker/types/RelationPickerHotkeyScope';
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 { import {
CommentableType, CommentableType,
CommentThread, CommentThread,
CommentThreadTarget, CommentThreadTarget,
useSearchCompanyQuery,
useSearchPeopleQuery,
} from '~/generated/graphql'; } from '~/generated/graphql';
type OwnProps = { type OwnProps = {
@ -90,35 +87,14 @@ export function CommentThreadRelationPicker({ commentThread }: OwnProps) {
?.filter((relation) => relation.commentableType === 'Company') ?.filter((relation) => relation.commentableType === 'Company')
.map((relation) => relation.commentableId) ?? []; .map((relation) => relation.commentableId) ?? [];
const personsForMultiSelect = useFilteredSearchEntityQuery({ const personsForMultiSelect = useFilteredSearchPeopleQuery({
queryHook: useSearchPeopleQuery,
searchOnFields: ['firstName', 'lastName'],
orderByField: 'lastName',
selectedIds: peopleIds,
mappingFunction: (entity) =>
({
id: entity.id,
entityType: CommentableType.Person,
name: `${entity.firstName} ${entity.lastName}`,
avatarType: 'rounded',
} as CommentableEntityForSelect),
searchFilter, searchFilter,
selectedIds: peopleIds,
}); });
const companiesForMultiSelect = useFilteredSearchEntityQuery({ const companiesForMultiSelect = useFilteredSearchCompanyQuery({
queryHook: useSearchCompanyQuery,
searchOnFields: ['name'],
orderByField: 'name',
selectedIds: companyIds,
mappingFunction: (company) =>
({
id: company.id,
entityType: CommentableType.Company,
name: company.name,
avatarUrl: getLogoUrlFromDomainName(company.domainName),
avatarType: 'squared',
} as CommentableEntityForSelect),
searchFilter, searchFilter,
selectedIds: companyIds,
}); });
const { const {

View File

@ -1,9 +1,9 @@
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect'; import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect';
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState'; import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState';
import { EntityForSelect } from '@/relation-picker/types/EntityForSelect'; import { EntityForSelect } from '@/relation-picker/types/EntityForSelect';
import { Entity } from '@/relation-picker/types/EntityTypeForSelect'; import { Entity } from '@/relation-picker/types/EntityTypeForSelect';
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
import { useEditableCell } from '@/ui/components/editable-cell/hooks/useEditableCell'; import { useEditableCell } from '@/ui/components/editable-cell/hooks/useEditableCell';
import { import {
Company, Company,

View File

@ -3,11 +3,9 @@ import { filterDropdownSearchInputScopedState } from '@/lib/filters-and-sorts/st
import { filterDropdownSelectedEntityIdScopedState } from '@/lib/filters-and-sorts/states/filterDropdownSelectedEntityIdScopedState'; import { filterDropdownSelectedEntityIdScopedState } from '@/lib/filters-and-sorts/states/filterDropdownSelectedEntityIdScopedState';
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
import { useRecoilScopedValue } from '@/recoil-scope/hooks/useRecoilScopedValue'; import { useRecoilScopedValue } from '@/recoil-scope/hooks/useRecoilScopedValue';
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
import { Entity } from '@/relation-picker/types/EntityTypeForSelect';
import { TableContext } from '@/ui/tables/states/TableContext'; import { TableContext } from '@/ui/tables/states/TableContext';
import { getLogoUrlFromDomainName } from '@/utils/utils';
import { useSearchCompanyQuery } from '~/generated/graphql'; import { useFilteredSearchCompanyQuery } from '../services';
export function FilterDropdownCompanySearchSelect() { export function FilterDropdownCompanySearchSelect() {
const filterDropdownSearchInput = useRecoilScopedValue( const filterDropdownSearchInput = useRecoilScopedValue(
@ -20,21 +18,11 @@ export function FilterDropdownCompanySearchSelect() {
TableContext, TableContext,
); );
const usersForSelect = useFilteredSearchEntityQuery({ const usersForSelect = useFilteredSearchCompanyQuery({
queryHook: useSearchCompanyQuery, searchFilter: filterDropdownSearchInput,
searchOnFields: ['name'],
orderByField: 'name',
selectedIds: filterDropdownSelectedEntityId selectedIds: filterDropdownSelectedEntityId
? [filterDropdownSelectedEntityId] ? [filterDropdownSelectedEntityId]
: [], : [],
mappingFunction: (company) => ({
id: company.id,
entityType: Entity.User,
name: `${company.name}`,
avatarType: 'squared',
avatarUrl: getLogoUrlFromDomainName(company.domainName),
}),
searchFilter: filterDropdownSearchInput,
}); });
return ( return (

View File

@ -2,31 +2,16 @@ import { useCallback } from 'react';
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect'; import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect';
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState'; import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState';
import { getLogoUrlFromDomainName } from '@/utils/utils';
import { CommentableType, useSearchCompanyQuery } from '~/generated/graphql'; import { useFilteredSearchCompanyQuery } from '../services';
export function NewCompanyBoardCard() { export function NewCompanyBoardCard() {
const [searchFilter] = useRecoilScopedState( const [searchFilter] = useRecoilScopedState(
relationPickerSearchFilterScopedState, relationPickerSearchFilterScopedState,
); );
const companies = useFilteredSearchEntityQuery({ const companies = useFilteredSearchCompanyQuery({ searchFilter });
queryHook: useSearchCompanyQuery,
selectedIds: [],
searchFilter: searchFilter,
mappingFunction: (company) => ({
entityType: CommentableType.Company,
id: company.id,
name: company.name,
domainName: company.domainName,
avatarType: 'squared',
avatarUrl: getLogoUrlFromDomainName(company.domainName),
}),
orderByField: 'name',
searchOnFields: ['name'],
});
const handleEntitySelect = useCallback(async (companyId: string) => { const handleEntitySelect = useCallback(async (companyId: string) => {
return; return;

View File

@ -11,20 +11,18 @@ import { pipelineStageIdScopedState } from '@/pipeline-progress/states/pipelineS
import { RecoilScope } from '@/recoil-scope/components/RecoilScope'; import { RecoilScope } from '@/recoil-scope/components/RecoilScope';
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect'; import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect';
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState'; import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState';
import { RelationPickerHotkeyScope } from '@/relation-picker/types/RelationPickerHotkeyScope'; import { RelationPickerHotkeyScope } from '@/relation-picker/types/RelationPickerHotkeyScope';
import { BoardPipelineStageColumn } from '@/ui/board/components/Board'; import { BoardPipelineStageColumn } from '@/ui/board/components/Board';
import { NewButton } from '@/ui/board/components/NewButton'; import { NewButton } from '@/ui/board/components/NewButton';
import { getLogoUrlFromDomainName } from '@/utils/utils';
import { import {
CommentableType,
PipelineProgressableType, PipelineProgressableType,
useCreateOnePipelineProgressMutation, useCreateOnePipelineProgressMutation,
useSearchCompanyQuery,
} from '~/generated/graphql'; } from '~/generated/graphql';
import { currentPipelineState } from '~/pages/opportunities/currentPipelineState'; import { currentPipelineState } from '~/pages/opportunities/currentPipelineState';
import { useFilteredSearchCompanyQuery } from '../services';
export function NewCompanyProgressButton() { export function NewCompanyProgressButton() {
const [isCreatingCard, setIsCreatingCard] = useState(false); const [isCreatingCard, setIsCreatingCard] = useState(false);
const [board, setBoard] = useRecoilState(boardState); const [board, setBoard] = useRecoilState(boardState);
@ -93,21 +91,7 @@ export function NewCompanyProgressButton() {
const [searchFilter] = useRecoilScopedState( const [searchFilter] = useRecoilScopedState(
relationPickerSearchFilterScopedState, relationPickerSearchFilterScopedState,
); );
const companies = useFilteredSearchEntityQuery({ const companies = useFilteredSearchCompanyQuery({ searchFilter });
queryHook: useSearchCompanyQuery,
selectedIds: [],
searchFilter: searchFilter,
mappingFunction: (company) => ({
entityType: CommentableType.Company,
id: company.id,
name: company.name,
domainName: company.domainName,
avatarType: 'squared',
avatarUrl: getLogoUrlFromDomainName(company.domainName),
}),
orderByField: 'name',
searchOnFields: ['name'],
});
return ( return (
<> <>

View File

@ -1,11 +1,16 @@
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import { CommentableEntityForSelect } from '@/comments/types/CommentableEntityForSelect';
import { SelectedSortType } from '@/lib/filters-and-sorts/interfaces/sorts/interface'; import { SelectedSortType } from '@/lib/filters-and-sorts/interfaces/sorts/interface';
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
import { getLogoUrlFromDomainName } from '@/utils/utils';
import { import {
CommentableType,
CompanyOrderByWithRelationInput as Companies_Order_By, CompanyOrderByWithRelationInput as Companies_Order_By,
CompanyWhereInput as Companies_Bool_Exp, CompanyWhereInput as Companies_Bool_Exp,
SortOrder as Order_By, SortOrder as Order_By,
useGetCompaniesQuery, useGetCompaniesQuery,
useSearchCompanyQuery,
} from '~/generated/graphql'; } from '~/generated/graphql';
export type CompaniesSelectedSortType = SelectedSortType<Companies_Order_By>; export type CompaniesSelectedSortType = SelectedSortType<Companies_Order_By>;
@ -41,6 +46,33 @@ export function useCompaniesQuery(
return useGetCompaniesQuery({ variables: { orderBy, where } }); return useGetCompaniesQuery({ variables: { orderBy, where } });
} }
export function useFilteredSearchCompanyQuery({
searchFilter,
selectedIds = [],
limit,
}: {
searchFilter: string;
selectedIds?: string[];
limit?: number;
}) {
return useFilteredSearchEntityQuery({
queryHook: useSearchCompanyQuery,
searchOnFields: ['name'],
orderByField: 'name',
selectedIds: selectedIds,
mappingFunction: (company) =>
({
id: company.id,
entityType: CommentableType.Company,
name: company.name,
avatarUrl: getLogoUrlFromDomainName(company.domainName),
avatarType: 'squared',
} as CommentableEntityForSelect),
searchFilter,
limit,
});
}
export const defaultOrderBy: Companies_Order_By[] = [ export const defaultOrderBy: Companies_Order_By[] = [
{ {
createdAt: Order_By.Desc, createdAt: Order_By.Desc,

View File

@ -1,23 +1,16 @@
import { Key } from 'ts-key-enum'; import { Key } from 'ts-key-enum';
import { useFilteredSearchCompanyQuery } from '@/companies/services';
import { useScopedHotkeys } from '@/lib/hotkeys/hooks/useScopedHotkeys'; import { useScopedHotkeys } from '@/lib/hotkeys/hooks/useScopedHotkeys';
import { useSetHotkeyScope } from '@/lib/hotkeys/hooks/useSetHotkeyScope'; import { useSetHotkeyScope } from '@/lib/hotkeys/hooks/useSetHotkeyScope';
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect'; import { SingleEntitySelect } from '@/relation-picker/components/SingleEntitySelect';
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState'; import { relationPickerSearchFilterScopedState } from '@/relation-picker/states/relationPickerSearchFilterScopedState';
import { RelationPickerHotkeyScope } from '@/relation-picker/types/RelationPickerHotkeyScope'; import { RelationPickerHotkeyScope } from '@/relation-picker/types/RelationPickerHotkeyScope';
import { useEditableCell } from '@/ui/components/editable-cell/hooks/useEditableCell'; import { useEditableCell } from '@/ui/components/editable-cell/hooks/useEditableCell';
import { isCreateModeScopedState } from '@/ui/components/editable-cell/states/isCreateModeScopedState'; import { isCreateModeScopedState } from '@/ui/components/editable-cell/states/isCreateModeScopedState';
import { TableHotkeyScope } from '@/ui/tables/types/TableHotkeyScope'; import { TableHotkeyScope } from '@/ui/tables/types/TableHotkeyScope';
import { getLogoUrlFromDomainName } from '@/utils/utils'; import { Company, Person, useUpdatePeopleMutation } from '~/generated/graphql';
import {
CommentableType,
Company,
Person,
useSearchCompanyQuery,
useUpdatePeopleMutation,
} from '~/generated/graphql';
export type OwnProps = { export type OwnProps = {
people: Pick<Person, 'id'> & { company?: Pick<Company, 'id'> | null }; people: Pick<Person, 'id'> & { company?: Pick<Company, 'id'> | null };
@ -35,19 +28,9 @@ export function PeopleCompanyPicker({ people }: OwnProps) {
const addToScopeStack = useSetHotkeyScope(); const addToScopeStack = useSetHotkeyScope();
const companies = useFilteredSearchEntityQuery({ const companies = useFilteredSearchCompanyQuery({
queryHook: useSearchCompanyQuery, searchFilter,
selectedIds: [people.company?.id ?? ''], selectedIds: people.company?.id ? [people.company.id] : [],
searchFilter: searchFilter,
mappingFunction: (company) => ({
entityType: CommentableType.Company,
id: company.id,
name: company.name,
avatarType: 'squared',
avatarUrl: getLogoUrlFromDomainName(company.domainName),
}),
orderByField: 'name',
searchOnFields: ['name'],
}); });
async function handleEntitySelected(entity: any) { async function handleEntitySelected(entity: any) {

View File

@ -1,11 +1,15 @@
import { gql } from '@apollo/client'; import { gql } from '@apollo/client';
import { CommentableEntityForSelect } from '@/comments/types/CommentableEntityForSelect';
import { SelectedSortType } from '@/lib/filters-and-sorts/interfaces/sorts/interface'; import { SelectedSortType } from '@/lib/filters-and-sorts/interfaces/sorts/interface';
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
import { import {
CommentableType,
PersonOrderByWithRelationInput as People_Order_By, PersonOrderByWithRelationInput as People_Order_By,
PersonWhereInput as People_Bool_Exp, PersonWhereInput as People_Bool_Exp,
SortOrder, SortOrder,
useGetPeopleQuery, useGetPeopleQuery,
useSearchPeopleQuery,
} from '~/generated/graphql'; } from '~/generated/graphql';
export type PeopleSelectedSortType = SelectedSortType<People_Order_By>; export type PeopleSelectedSortType = SelectedSortType<People_Order_By>;
@ -43,6 +47,32 @@ export function usePeopleQuery(
}); });
} }
export function useFilteredSearchPeopleQuery({
searchFilter,
selectedIds = [],
limit,
}: {
searchFilter: string;
selectedIds?: string[];
limit?: number;
}) {
return useFilteredSearchEntityQuery({
queryHook: useSearchPeopleQuery,
searchOnFields: ['firstName', 'lastName'],
orderByField: 'lastName',
selectedIds: selectedIds,
mappingFunction: (entity) =>
({
id: entity.id,
entityType: CommentableType.Person,
name: `${entity.firstName} ${entity.lastName}`,
avatarType: 'rounded',
} as CommentableEntityForSelect),
searchFilter,
limit,
});
}
export const defaultOrderBy: People_Order_By[] = [ export const defaultOrderBy: People_Order_By[] = [
{ {
createdAt: SortOrder.Desc, createdAt: SortOrder.Desc,

View File

@ -3,8 +3,8 @@ import { filterDropdownSearchInputScopedState } from '@/lib/filters-and-sorts/st
import { filterDropdownSelectedEntityIdScopedState } from '@/lib/filters-and-sorts/states/filterDropdownSelectedEntityIdScopedState'; import { filterDropdownSelectedEntityIdScopedState } from '@/lib/filters-and-sorts/states/filterDropdownSelectedEntityIdScopedState';
import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState'; import { useRecoilScopedState } from '@/recoil-scope/hooks/useRecoilScopedState';
import { useRecoilScopedValue } from '@/recoil-scope/hooks/useRecoilScopedValue'; import { useRecoilScopedValue } from '@/recoil-scope/hooks/useRecoilScopedValue';
import { useFilteredSearchEntityQuery } from '@/relation-picker/hooks/useFilteredSearchEntityQuery';
import { Entity } from '@/relation-picker/types/EntityTypeForSelect'; import { Entity } from '@/relation-picker/types/EntityTypeForSelect';
import { useFilteredSearchEntityQuery } from '@/search/hooks/useFilteredSearchEntityQuery';
import { TableContext } from '@/ui/tables/states/TableContext'; import { TableContext } from '@/ui/tables/states/TableContext';
import { useSearchUserQuery } from '~/generated/graphql'; import { useSearchUserQuery } from '~/generated/graphql';