Skip to content

Commit

Permalink
QF 1272 search autocomplete (#2250)
Browse files Browse the repository at this point in the history
* Handle search drawer no results

* Open commandBar on search page input type

* Sync state between search page and command bar initial input

* Update styling

* QF-1276 full search (#2252)

Full search
  • Loading branch information
osamasayed authored Dec 1, 2024
1 parent 8dc1805 commit 0233f06
Show file tree
Hide file tree
Showing 28 changed files with 323 additions and 419 deletions.
13 changes: 1 addition & 12 deletions src/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
makeAudioTimestampsUrl,
makeChapterAudioDataUrl,
makeAvailableRecitersUrl,
makeSearchResultsUrl,
makeTranslationsInfoUrl,
makeTranslationsUrl,
makeVersesUrl,
Expand All @@ -31,10 +30,9 @@ import {
} from '@/utils/apiPaths';
import generateSignature from '@/utils/auth/signature';
import { isStaticBuild } from '@/utils/build';
import { SearchRequest, AdvancedCopyRequest, PagesLookUpRequest } from 'types/ApiRequests';
import { AdvancedCopyRequest, PagesLookUpRequest } from 'types/ApiRequests';
import {
TranslationsResponse,
SearchResponse,
AdvancedCopyRawResultResponse,
LanguagesResponse,
RecitersResponse,
Expand Down Expand Up @@ -244,15 +242,6 @@ export const getAdvancedCopyRawResult = async (
params: AdvancedCopyRequest,
): Promise<AdvancedCopyRawResultResponse> => fetcher(makeAdvancedCopyUrl(params));

/**
* Get the search results of a query.
*
* @param {SearchRequest} params
* @returns {Promise<SearchResponse>}
*/
export const getSearchResults = async (params: SearchRequest): Promise<SearchResponse> =>
fetcher(makeSearchResultsUrl(params));

/**
* Get the search results of a query.
*
Expand Down
26 changes: 8 additions & 18 deletions src/components/CommandBar/CommandBarBody/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,15 @@ import VoiceSearchBodyContainer from '@/components/TarteelVoiceSearch/BodyContai
import TarteelVoiceSearchTrigger from '@/components/TarteelVoiceSearch/Trigger';
import useDebounce from '@/hooks/useDebounce';
import IconSearch from '@/icons/search.svg';
import { selectRecentNavigations } from '@/redux/slices/CommandBar/state';
import { selectInitialSearchQuery, selectRecentNavigations } from '@/redux/slices/CommandBar/state';
import { selectIsCommandBarVoiceFlowStarted } from '@/redux/slices/voiceSearch';
import { SearchMode } from '@/types/Search/SearchRequestParams';
import SearchQuerySource from '@/types/SearchQuerySource';
import { makeNewSearchResultsUrl } from '@/utils/apiPaths';
import { areArraysEqual } from '@/utils/array';
import { logButtonClick, logTextSearchQuery } from '@/utils/eventLogger';
import { getQuickSearchQuery } from '@/utils/search';
import { SearchResponse } from 'types/ApiResponses';
import { SearchNavigationType } from 'types/SearchNavigationResult';
import { SearchNavigationType } from 'types/Search/SearchNavigationResult';

const NAVIGATE_TO = [
{
Expand Down Expand Up @@ -66,7 +66,8 @@ const CommandBarBody: React.FC = () => {
const { t } = useTranslation('common');
const recentNavigations = useSelector(selectRecentNavigations, areArraysEqual);
const isVoiceSearchFlowStarted = useSelector(selectIsCommandBarVoiceFlowStarted, shallowEqual);
const [searchQuery, setSearchQuery] = useState<string>(null);
const initialSearchQuery = useSelector(selectInitialSearchQuery, shallowEqual);
const [searchQuery, setSearchQuery] = useState<string>(initialSearchQuery || null);
// Debounce search query to avoid having to call the API on every type. The API will be called once the user stops typing.
const debouncedSearchQuery = useDebounce<string>(searchQuery, DEBOUNCING_PERIOD_MS);

Expand Down Expand Up @@ -115,12 +116,7 @@ const CommandBarBody: React.FC = () => {
);

const quickSearchFetcher = useCallback(() => {
return getNewSearchResults({
mode: SearchMode.Quick,
query: searchQuery,
getText: 1,
highlight: 1,
});
return getNewSearchResults(getQuickSearchQuery(searchQuery));
}, [searchQuery]);

/**
Expand Down Expand Up @@ -191,6 +187,7 @@ const CommandBarBody: React.FC = () => {
inputMode="text"
// eslint-disable-next-line jsx-a11y/no-autofocus
autoFocus
value={searchQuery}
/>
</div>
)}
Expand All @@ -210,14 +207,7 @@ const CommandBarBody: React.FC = () => {
) : (
<DataFetcher
queryKey={
searchQuery
? makeNewSearchResultsUrl({
mode: SearchMode.Quick,
query: searchQuery,
getText: 1,
highlight: 1,
})
: null
searchQuery ? makeNewSearchResultsUrl(getQuickSearchQuery(searchQuery)) : null
}
render={dataFetcherRender}
fetcher={quickSearchFetcher}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import styles from './CommandPrefix.module.scss';
import DataContext from '@/contexts/DataContext';
import NavigateIcon from '@/icons/east.svg';
import { getSearchNavigationResult } from '@/utils/search';
import { SearchNavigationType } from 'types/SearchNavigationResult';
import { SearchNavigationType } from 'types/Search/SearchNavigationResult';

interface Props {
name: string;
Expand Down
2 changes: 1 addition & 1 deletion src/components/CommandBar/CommandsList/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import {
} from '@/redux/slices/CommandBar/state';
import { logButtonClick } from '@/utils/eventLogger';
import { resolveUrlBySearchNavigationType } from '@/utils/navigation';
import { SearchNavigationResult } from 'types/SearchNavigationResult';
import { SearchNavigationResult } from 'types/Search/SearchNavigationResult';

export interface Command extends SearchNavigationResult {
group: string;
Expand Down
11 changes: 3 additions & 8 deletions src/components/Navbar/SearchDrawer/SearchDrawer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,11 @@ import useFocus from '@/hooks/useFocusElement';
import { selectNavbar } from '@/redux/slices/navbar';
import { selectSelectedTranslations } from '@/redux/slices/QuranReader/translations';
import { selectIsSearchDrawerVoiceFlowStarted } from '@/redux/slices/voiceSearch';
import { SearchMode } from '@/types/Search/SearchRequestParams';
import SearchService from '@/types/Search/SearchService';
import SearchQuerySource from '@/types/SearchQuerySource';
import { areArraysEqual } from '@/utils/array';
import { logButtonClick, logTextSearchQuery } from '@/utils/eventLogger';
import { addToSearchHistory } from '@/utils/search';
import { addToSearchHistory, getQuickSearchQuery } from '@/utils/search';
import { SearchResponse } from 'types/ApiResponses';

const SearchBodyContainer = dynamic(() => import('@/components/Search/SearchBodyContainer'), {
Expand Down Expand Up @@ -63,12 +62,7 @@ const SearchDrawer: React.FC = () => {
addToSearchHistory(dispatch, debouncedSearchQuery, SearchQuerySource.SearchDrawer);
setIsSearching(true);
logTextSearchQuery(debouncedSearchQuery, SearchQuerySource.SearchDrawer);
getNewSearchResults({
mode: SearchMode.Quick,
query: debouncedSearchQuery,
getText: 1,
highlight: 1,
})
getNewSearchResults(getQuickSearchQuery(debouncedSearchQuery))
.then((response) => {
setSearchResult({
...response,
Expand Down Expand Up @@ -150,6 +144,7 @@ const SearchDrawer: React.FC = () => {
searchResult={searchResult}
isSearching={isSearching}
hasError={hasError}
shouldSuggestFullSearchWhenNoResults
/>
)}
</>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Search/NavigationItem/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { logButtonClick } from '@/utils/eventLogger';
import { toLocalizedNumber, toLocalizedVerseKey } from '@/utils/locale';
import { resolveUrlBySearchNavigationType } from '@/utils/navigation';
import { getSearchNavigationResult } from '@/utils/search';
import { SearchNavigationResult, SearchNavigationType } from 'types/SearchNavigationResult';
import { SearchNavigationResult, SearchNavigationType } from 'types/Search/SearchNavigationResult';

interface Props {
navigation: SearchNavigationResult;
Expand All @@ -24,7 +24,7 @@ interface Props {
const NavigationItem: React.FC<Props> = ({
navigation,
isSearchDrawer,
service = SearchService.QDC,
service = SearchService.KALIMAT,
}) => {
const { t, lang } = useTranslation('common');
const chaptersData = useContext(DataContext);
Expand Down
25 changes: 24 additions & 1 deletion src/components/Search/NoResults/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,37 @@ import useTranslation from 'next-translate/useTranslation';

import styles from './NoResults.module.scss';

import Link, { LinkVariant } from '@/dls/Link/Link';
import IconSearch from '@/icons/search.svg';
import { logButtonClick } from '@/utils/eventLogger';
import { getSearchQueryNavigationUrl } from '@/utils/navigation';

interface Props {
searchQuery: string;
shouldSuggestFullSearchWhenNoResults?: boolean;
}

const NoResults: React.FC<Props> = ({ searchQuery }) => {
const NoResults: React.FC<Props> = ({
searchQuery,
shouldSuggestFullSearchWhenNoResults = false,
}) => {
const { t } = useTranslation('common');
if (shouldSuggestFullSearchWhenNoResults) {
return (
<Link
href={getSearchQueryNavigationUrl(searchQuery)}
shouldPassHref
onClick={() => {
logButtonClick('no_results_advanced_search_link');
}}
variant={LinkVariant.Blend}
>
{t('search-for', {
searchQuery,
})}
</Link>
);
}
return (
<>
<div className={styles.container}>
Expand Down
7 changes: 6 additions & 1 deletion src/components/Search/SearchBodyContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ interface Props {
currentPage?: number;
pageSize?: number;
onPageChange?: (page: number) => void;
shouldSuggestFullSearchWhenNoResults?: boolean;
}

const SearchBodyContainer: React.FC<Props> = ({
Expand All @@ -35,6 +36,7 @@ const SearchBodyContainer: React.FC<Props> = ({
currentPage,
pageSize,
onPageChange,
shouldSuggestFullSearchWhenNoResults = false,
}) => {
const { t } = useTranslation('common');
const isEmptyResponse =
Expand All @@ -61,7 +63,10 @@ const SearchBodyContainer: React.FC<Props> = ({
{!hasError && searchResult && (
<>
{isEmptyResponse ? (
<NoResults searchQuery={searchQuery} />
<NoResults
searchQuery={searchQuery}
shouldSuggestFullSearchWhenNoResults={shouldSuggestFullSearchWhenNoResults}
/>
) : (
<SearchResults
onSearchResultClicked={onSearchResultClicked}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ import styles from './SearchResultItem.module.scss';

import DataContext from '@/contexts/DataContext';
import Link from '@/dls/Link/Link';
import { SearchNavigationType } from '@/types/Search/SearchNavigationResult';
import SearchService from '@/types/Search/SearchService';
import { SearchNavigationType } from '@/types/SearchNavigationResult';
import SearchQuerySource from '@/types/SearchQuerySource';
import { getChapterData } from '@/utils/chapter';
import { logButtonClick } from '@/utils/eventLogger';
Expand Down
22 changes: 5 additions & 17 deletions src/components/Search/SearchResults/SearchResultItem.module.scss
Original file line number Diff line number Diff line change
@@ -1,19 +1,3 @@
.translationName {
font-size: var(--font-size-xsmall);
opacity: var(--opacity-75);
}

.translationContainer {
margin-block-start: var(--spacing-small);
margin-block-end: var(--spacing-small);
margin-inline-start: 0;
margin-inline-end: 0;
em {
font-weight: var(--font-weight-semibold);
text-decoration: underline;
}
}

.container {
text-decoration: none;
border-block-end: 1px solid var(--color-borders-hairline);
Expand All @@ -30,11 +14,15 @@
.quranTextResult {
font-size: var(--font-size-xlarge);
line-height: var(--line-height-large);
direction: rtl;
padding-block-start: var(--spacing-micro);
padding-block-end: var(--spacing-micro);
padding-inline-start: var(--spacing-micro);
padding-inline-end: var(--spacing-micro);

em {
font-weight: var(--font-weight-semibold);
text-decoration: underline;
}
}

.verseKey {
Expand Down
Loading

0 comments on commit 0233f06

Please sign in to comment.