forked from freeCodeCamp/freeCodeCamp
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
chore: update react-instancesearch to v7 (freeCodeCamp#57020)
Co-authored-by: Huyen Nguyen <[email protected]> Co-authored-by: Oliver Eyton-Williams <[email protected]>
- Loading branch information
1 parent
6c34c2b
commit 228c231
Showing
13 changed files
with
872 additions
and
361 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
169 changes: 69 additions & 100 deletions
169
client/src/components/search/searchBar/search-hits.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,118 +1,87 @@ | ||
import { isEmpty } from 'lodash-es'; | ||
import React, { useEffect } from 'react'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { SearchState, Hit } from 'react-instantsearch-core'; | ||
import { connectStateResults, connectHits } from 'react-instantsearch-dom'; | ||
import { useHits } from 'react-instantsearch'; | ||
import { searchPageUrl } from '../../../utils/algolia-locale-setup'; | ||
import NoHitsSuggestion from './no-hits-suggestion'; | ||
import Suggestion from './search-suggestion'; | ||
import NoHitsSuggestion from './no-hits-suggestion'; | ||
import type { Hit } from './types'; | ||
|
||
const searchUrl = searchPageUrl; | ||
interface CustomHitsProps { | ||
// eslint-disable-next-line @typescript-eslint/no-explicit-any | ||
hits: Array<any>; | ||
searchQuery: string; | ||
handleMouseEnter: (e: React.SyntheticEvent<HTMLElement, Event>) => void; | ||
handleMouseLeave: (e: React.SyntheticEvent<HTMLElement, Event>) => void; | ||
selectedIndex: number; | ||
handleHits: (currHits: Array<Hit>) => void; | ||
} | ||
|
||
interface SearchHitsProps { | ||
searchState: SearchState; | ||
handleMouseEnter: (e: React.SyntheticEvent<HTMLElement, Event>) => void; | ||
handleMouseLeave: (e: React.SyntheticEvent<HTMLElement, Event>) => void; | ||
handleHits: (hits: Hit[]) => void; | ||
selectedIndex: number; | ||
handleHits: (currHits: Array<Hit>) => void; | ||
} | ||
const CustomHits = connectHits( | ||
({ | ||
hits, | ||
searchQuery, | ||
handleMouseEnter, | ||
handleMouseLeave, | ||
selectedIndex, | ||
handleHits | ||
}: CustomHitsProps) => { | ||
const { t } = useTranslation(); | ||
const noHits = isEmpty(hits); | ||
const noHitsTitle = t('search.no-tutorials'); | ||
const footer = [ | ||
{ | ||
objectID: `footer-${searchQuery}`, | ||
query: searchQuery, | ||
url: noHits | ||
? null | ||
: `${searchUrl}?query=${encodeURIComponent(searchQuery)}`, | ||
title: t('search.see-results', { searchQuery: searchQuery }), | ||
_highlightResult: { | ||
query: { | ||
value: ` | ||
<ais-highlight-0000000000> | ||
${t('search.see-results', { searchQuery: searchQuery })} | ||
</ais-highlight-0000000000> | ||
` | ||
} | ||
|
||
function SearchHits({ | ||
handleMouseEnter, | ||
handleMouseLeave, | ||
handleHits, | ||
selectedIndex | ||
}: SearchHitsProps) { | ||
const { results } = useHits<Hit>(); | ||
const query = results ? results.query : ''; | ||
const { t } = useTranslation(); | ||
|
||
const noHits = isEmpty(results?.hits); | ||
const noHitsTitle = t('search.no-tutorials'); | ||
|
||
const footer = [ | ||
{ | ||
__position: 8, | ||
objectID: `footer-${query}`, | ||
query: query, | ||
url: noHits ? '' : `${searchUrl}?query=${encodeURIComponent(query)}`, | ||
_highlightResult: { | ||
query: { | ||
value: `${t('search.see-results', { searchQuery: query })}`, | ||
matchLevel: 'none' as const, | ||
matchedWords: [] | ||
} | ||
} | ||
]; | ||
const allHits = hits.slice(0, 8).concat(footer); | ||
useEffect(() => { | ||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument | ||
handleHits(allHits); | ||
}); | ||
} | ||
]; | ||
const allHits: Hit[] = | ||
results?.hits && results?.query ? [...results.hits, ...footer] : []; | ||
|
||
return ( | ||
<div className='ais-Hits'> | ||
<ul className='ais-Hits-list' aria-label={t('search.result-list')}> | ||
{allHits.map((hit: Hit, i: number) => ( | ||
<li | ||
className={ | ||
!noHits && i === selectedIndex | ||
? 'ais-Hits-item selected' | ||
: 'ais-Hits-item' | ||
} | ||
data-fccobjectid={hit.objectID} | ||
key={hit.objectID} | ||
> | ||
{noHits ? ( | ||
<NoHitsSuggestion | ||
handleMouseEnter={handleMouseEnter} | ||
handleMouseLeave={handleMouseLeave} | ||
title={noHitsTitle} | ||
/> | ||
) : ( | ||
<Suggestion | ||
handleMouseEnter={handleMouseEnter} | ||
handleMouseLeave={handleMouseLeave} | ||
hit={hit} | ||
/> | ||
)} | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
); | ||
} | ||
); | ||
useEffect(() => { | ||
handleHits(allHits); | ||
}); | ||
|
||
const SearchHits = connectStateResults( | ||
({ | ||
searchState, | ||
handleMouseEnter, | ||
handleMouseLeave, | ||
selectedIndex, | ||
handleHits | ||
}: SearchHitsProps) => { | ||
return isEmpty(searchState) || !searchState.query ? null : ( | ||
<CustomHits | ||
handleHits={handleHits} | ||
handleMouseEnter={handleMouseEnter} | ||
handleMouseLeave={handleMouseLeave} | ||
searchQuery={searchState.query} | ||
selectedIndex={selectedIndex} | ||
/> | ||
); | ||
} | ||
); | ||
return ( | ||
<div className='ais-Hits'> | ||
<ul className='ais-Hits-list' aria-label={t('search.result-list')}> | ||
{allHits.map((hit: Hit, i: number) => ( | ||
<li | ||
className={ | ||
!noHits && i === selectedIndex | ||
? 'ais-Hits-item selected' | ||
: 'ais-Hits-item' | ||
} | ||
data-fccobjectid={hit.objectID} | ||
key={hit.objectID} | ||
> | ||
{noHits ? ( | ||
<NoHitsSuggestion | ||
handleMouseEnter={handleMouseEnter} | ||
handleMouseLeave={handleMouseLeave} | ||
title={noHitsTitle} | ||
/> | ||
) : ( | ||
<Suggestion | ||
handleMouseEnter={handleMouseEnter} | ||
handleMouseLeave={handleMouseLeave} | ||
hit={hit} | ||
/> | ||
)} | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
); | ||
} | ||
|
||
export default SearchHits; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.