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;
+};