diff --git a/components/search/AccountResult.tsx b/components/search/AccountResult.tsx index b2c18f74ecf..eb9ee557071 100644 --- a/components/search/AccountResult.tsx +++ b/components/search/AccountResult.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { Markup } from 'interweave'; import { useIntl } from 'react-intl'; import formatCollectiveType from '../../lib/i18n/collective-type'; @@ -6,22 +7,45 @@ import formatCollectiveType from '../../lib/i18n/collective-type'; import Avatar from '../Avatar'; import { Badge } from '../ui/Badge'; +import { getHighlightsFields } from './lib'; +import type { SearchHighlights } from './types'; import type { AccountResultData } from './useRecentlyVisited'; -export function AccountResult({ account }: { account: AccountResultData }) { +export function AccountResult({ account, highlights }: { account: AccountResultData; highlights?: SearchHighlights }) { const intl = useIntl(); + const highlightFields = getHighlightsFields(highlights, ['name', 'slug']); + const otherHighlight = Object.values(highlightFields.others)[0]?.[0]; return (
-
{account.name}
+
+ {highlightFields.top.name ? ( + + ) : ( + account.name + )} +
{formatCollectiveType(intl, account.type)}
-
@{account.slug}
+
+ @ + {highlightFields.top.slug ? ( + + ) : ( + account.slug + )} + {otherHighlight && ( + + {' ยท '} + + + )} +
); diff --git a/components/search/ExpenseResult.tsx b/components/search/ExpenseResult.tsx index ef6e6f7b5b9..dbed87d755d 100644 --- a/components/search/ExpenseResult.tsx +++ b/components/search/ExpenseResult.tsx @@ -1,4 +1,5 @@ import React from 'react'; +import { Markup } from 'interweave'; import { useIntl } from 'react-intl'; import { ExpenseType } from '../../lib/graphql/types/v2/schema'; @@ -6,22 +7,38 @@ import { i18nExpenseType } from '../../lib/i18n/expense'; import Avatar from '../Avatar'; +import { getHighlightsFields } from './lib'; +import type { SearchHighlights } from './types'; import type { ExpenseResultData } from './useRecentlyVisited'; -export function ExpenseResult({ expense }: { expense: ExpenseResultData }) { +export function ExpenseResult({ expense, highlights }: { expense: ExpenseResultData; highlights?: SearchHighlights }) { const intl = useIntl(); + const highlightFields = getHighlightsFields(highlights, ['description']); + const otherHighlight = Object.values(highlightFields.others)[0]?.[0]; return (
-
{expense.description}
+
+ {' '} + {highlightFields.top.description ? ( + + ) : ( + expense.description + )} +
- {i18nExpenseType(intl, expense.type)} + {expense.type !== ExpenseType.UNCLASSIFIED && i18nExpenseType(intl, expense.type)} {expense.type === ExpenseType.RECEIPT && ' request'} to{' '} {expense.account.name} from{' '} {expense.payee.name}
+ {otherHighlight && ( +
+ +
+ )}
); diff --git a/components/search/SearchCommand.tsx b/components/search/SearchCommand.tsx index eaf5470bd73..0301533c4f3 100644 --- a/components/search/SearchCommand.tsx +++ b/components/search/SearchCommand.tsx @@ -189,7 +189,7 @@ export const SearchCommand = ({ open, setOpen }) => { {isLoading && } - + {recentlyVisited.length > 0 && debouncedInput === '' && ( @@ -221,7 +221,7 @@ export const SearchCommand = ({ open, setOpen }) => { nodes={data?.search.results.accounts.collection.nodes} renderNode={account => ( handleResultSelect({ type: 'account', data: account })}> - + )} /> @@ -233,7 +233,7 @@ export const SearchCommand = ({ open, setOpen }) => { input={debouncedInput} renderNode={expense => ( handleResultSelect({ type: 'expense', data: expense })}> - + )} /> @@ -248,7 +248,10 @@ export const SearchCommand = ({ open, setOpen }) => { key={transaction.id} onSelect={() => handleResultSelect({ type: 'transaction', data: transaction })} > - + )} /> diff --git a/components/search/TransactionResult.tsx b/components/search/TransactionResult.tsx index 7dc272cdc2b..cd37efa09a6 100644 --- a/components/search/TransactionResult.tsx +++ b/components/search/TransactionResult.tsx @@ -1,5 +1,6 @@ import React from 'react'; import clsx from 'clsx'; +import { Markup } from 'interweave'; import { ArrowDown, ArrowUp } from 'lucide-react'; import { useIntl } from 'react-intl'; @@ -7,10 +8,20 @@ import { i18nTransactionKind } from '../../lib/i18n/transaction'; import FormattedMoneyAmount from '../FormattedMoneyAmount'; +import { getHighlightsFields } from './lib'; +import type { SearchHighlights } from './types'; import type { TransactionResultData } from './useRecentlyVisited'; -export function TransactionResult({ transaction }: { transaction: TransactionResultData }) { +export function TransactionResult({ + transaction, + highlights, +}: { + transaction: TransactionResultData; + highlights?: SearchHighlights; +}) { const intl = useIntl(); + const highlightFields = getHighlightsFields(highlights, []); + const otherHighlight = Object.values(highlightFields.others)[0]?.[0]; return (
+ {otherHighlight && ( +
+ +
+ )} ); } diff --git a/components/search/lib.ts b/components/search/lib.ts new file mode 100644 index 00000000000..63fa047c850 --- /dev/null +++ b/components/search/lib.ts @@ -0,0 +1,24 @@ +import type { SearchHighlights } from './types'; + +export function getHighlightsFields( + highlights: SearchHighlights, + topFields: readonly T[], +): { + others: Record; + top: Record; +} { + const top: Record = {}; + const others: Record = {}; + + if (highlights?.fields) { + for (const [field, values] of Object.entries(highlights.fields)) { + if (topFields.includes(field as T)) { + top[field as T] = values; + } else { + others[field] = values; + } + } + } + + return { top: top as Record, others }; +} diff --git a/components/search/queries.ts b/components/search/queries.ts index 3b8b69679a8..c4e45facf54 100644 --- a/components/search/queries.ts +++ b/components/search/queries.ts @@ -11,6 +11,7 @@ export const searchCommandQuery = gql` search(searchTerm: $searchTerm, defaultLimit: $limit, host: $host, account: $account) { results { accounts { + highlights collection { totalCount limit @@ -24,6 +25,7 @@ export const searchCommandQuery = gql` } } expenses { + highlights collection { totalCount limit @@ -55,6 +57,7 @@ export const searchCommandQuery = gql` } } transactions @include(if: $includeTransactions) { + highlights collection { totalCount limit diff --git a/components/search/types.ts b/components/search/types.ts new file mode 100644 index 00000000000..f8f4f9bdf16 --- /dev/null +++ b/components/search/types.ts @@ -0,0 +1,4 @@ +export type SearchHighlights = { + score: number; + fields: Record; +};