Skip to content

Commit

Permalink
Display the top artists as part of the results
Browse files Browse the repository at this point in the history
  • Loading branch information
Kerollmops committed May 18, 2024
1 parent 0dea433 commit fbc8400
Show file tree
Hide file tree
Showing 7 changed files with 106 additions and 86 deletions.
13 changes: 8 additions & 5 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { instantMeiliSearch as instantMeilisearch } from '@meilisearch/instant-m
import { MeiliSearch as Meilisearch } from 'meilisearch'

import ApiKeyContext from 'context/ApiKeyContext'
import { ArtistsProvider } from 'context/ArtistsContext'
import { useMeilisearchClientContext } from 'context/MeilisearchClientContext'
import useLocalStorage from 'hooks/useLocalStorage'
import Body from 'components/Body'
Expand Down Expand Up @@ -47,11 +48,13 @@ const App = () => {
}, [apiKey])

return (
<ApiKeyContext.Provider value={{ apiKey, setApiKey }}>
<Wrapper>
<Body currentIndex={currentIndex} setCurrentIndex={setCurrentIndex} />
</Wrapper>
</ApiKeyContext.Provider>
<ArtistsProvider>
<ApiKeyContext.Provider value={{ apiKey, setApiKey }}>
<Wrapper>
<Body currentIndex={currentIndex} setCurrentIndex={setCurrentIndex} />
</Wrapper>
</ApiKeyContext.Provider>
</ArtistsProvider>
)
}

Expand Down
9 changes: 9 additions & 0 deletions src/components/Body.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React from 'react'
import { InstantSearch } from 'react-instantsearch-dom'

import { useMeilisearchClientContext } from 'context/MeilisearchClientContext'
import { useArtists } from 'context/ArtistsContext'
import Box from 'components/Box'
import Header from 'components/Header/index'
import BodyWrapper from 'components/BodyWrapper'
Expand All @@ -28,11 +29,19 @@ const IndexContent = ({ currentIndex }) => {
const Body = ({ currentIndex, getIndexesList, setCurrentIndex }) => {
const { meilisearchJsClient, instantMeilisearchClient } =
useMeilisearchClientContext()
const { setArtists } = useArtists()

return (
<InstantSearch
indexName={currentIndex.uid}
searchClient={instantMeilisearchClient}
onSearchStateChange={(searchState) => {
const index = meilisearchJsClient.index('artists')
const search = index.search(searchState.query, {
attributesToHighlight: ['artist'],
})
search.then((s) => setArtists(s.hits))
}}
>
<Header
setCurrentIndex={setCurrentIndex}
Expand Down
43 changes: 0 additions & 43 deletions src/components/Header/index.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
import React from 'react'
import styled from 'styled-components'
import Color from 'color'
// import { DialogDisclosure, useDialogState } from 'reakit/Dialog'

import { useMeilisearchClientContext } from 'context/MeilisearchClientContext'
// import ApiKeyModalContent from 'components/ApiKeyModalContent'
// import Button from 'components/Button'
// import Link from 'components/Link'
// import Modal from 'components/Modal'
import Typography from 'components/Typography'
import SearchBox from 'components/SearchBox'
import Box from 'components/Box'
Expand All @@ -25,44 +20,6 @@ const HeaderWrapper = styled('div')(compose(position), {
zIndex: 3,
})

// const ApiKey = ({ requireApiKeyToWork }) => {
// const dialog = useDialogState()
// return (
// <>
// <DialogDisclosure {...dialog}>
// {(props) => (
// <Button
// icon={<Key style={{ height: 19 }} />}
// style={{ width: '100%' }}
// {...props}
// >
// Api Key
// </Button>
// )}
// </DialogDisclosure>
// <Modal
// title={`Enter your admin API key${
// requireApiKeyToWork ? '' : ' (optional)'
// }`}
// dialog={dialog}
// ariaLabel="settings-api-key"
// >
// {requireApiKeyToWork ? (
// <ApiKeyModalContent closeModal={() => dialog.hide()} />
// ) : (
// <Typography variant="typo11" color="gray.6">
// You haven’t set an API key yet, if you want to set one you can read
// the{' '}
// <Link href="https://docs.meilisearch.com/reference/api/keys.html">
// documentation
// </Link>
// </Typography>
// )}
// </Modal>
// </>
// )
// }

const Header = ({ currentIndex, refreshIndexes }) => {
const { meilisearchJsClient } = useMeilisearchClientContext()
const [version, setVersion] = React.useState()
Expand Down
54 changes: 54 additions & 0 deletions src/components/Results/ArtistHits.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import React, { useEffect } from 'react'
import styled from 'styled-components'
import 'react-lazy-load-image-component/src/effects/opacity.css'
import Box from 'components/Box'
import Card from 'components/Card'
import Typography from 'components/Typography'

const CustomCard = styled(Card)`
display: flex;
align-items: flex-start;
flex-wrap: wrap;
`

const MainContainer = styled.ul`
list-style: none;
padding-left: 0;
min-width: 300px;
`

const ArtistContainer = styled.li`
margin-bottom: 16px;
`

const ArtistHit = ({ hit }) => {
useEffect(() => {
if (!hit._highlightResult) {
// eslint-disable-next-line no-console
console.warn('Your hits have no field. Please check your index settings.')
}
}, [hit._highlightResult])

return (
<ArtistContainer>
<CustomCard>
<Box width={200} mr={4} flexShrink={0}>
{hit.artist}
</Box>
</CustomCard>
</ArtistContainer>
)
}

const ArtistHits = ({ hits, index, limit = 4 }) => (
<MainContainer>
<Typography variant="typo1" color="main.default" mb={3}>
Top Artists
</Typography>
{hits.slice(0, limit).map((artistHit) => (
<ArtistHit key={`artists-${index}-${artistHit.id}`} hit={artistHit} />
))}
</MainContainer>
)

export default ArtistHits
2 changes: 2 additions & 0 deletions src/components/Results/Highlight.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ const Highlight = connectHighlight(
hit,
})

console.log(hit)

Check warning on line 48 in src/components/Results/Highlight.js

View workflow job for this annotation

GitHub Actions / linter-check

Unexpected console statement

const croppedParts = cropPartsToMaxLength(parsedHit, maxLength)

return (
Expand Down
56 changes: 18 additions & 38 deletions src/components/Results/InfiniteHits.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import React from 'react'
import styled from 'styled-components'
import { useArtists } from 'context/ArtistsContext'
import { connectInfiniteHits, Configure } from 'react-instantsearch-dom'

import Button from 'components/Button'
import ScrollToTop from 'components/ScrollToTop'

import Hit from './Hit'
import ArtistHits from './ArtistHits'

const HitsList = styled.ul`
display: flex;
Expand All @@ -21,50 +23,28 @@ const HitsList = styled.ul`
}
`

const isAnImage = async (elem) => {
// Test the standard way with regex and image extensions
if (
typeof elem === 'string' &&
elem.match(/^(https|http):\/\/.*(jpe?g|png|gif|webp)(\?.*)?$/gi)
)
return true

if (typeof elem === 'string' && elem.match(/^https?:\/\//)) {
// Tries to load an image that is a valid URL but doesn't have a correct extension
return new Promise((resolve) => {
const img = new Image()
img.src = elem
img.onload = () => resolve(true)
img.onerror = () => resolve(false)
})
}
return false
}

const findImageKey = async (array) => {
const promises = array.map(async (elem) => isAnImage(elem[1]))
const results = await Promise.all(promises)
const index = results.findIndex((result) => result)
const imageField = array[index]
return imageField?.[0]
}

const InfiniteHits = connectInfiniteHits(({ hits, hasMore, refineNext }) => {
const [imageKey, setImageKey] = React.useState(false)
const { artists } = useArtists()

React.useEffect(() => {
const getImageKey = async () => {
setImageKey(hits[0] ? await findImageKey(Object.entries(hits[0])) : null)
}
getImageKey()
}, [hits[0]])
return (
<div>
<Configure hitsPerPage={21} />
<HitsList>
{hits.map((hit) => (
<Hit key={hit.id} hit={hit} imageKey={imageKey} />
))}
{hits.map((hit, index) => {
if (index === 2) {
return (
<>
<ArtistHits
key={`artists-${index}`}
hits={artists}
index={index}
/>
<Hit key={hit.id} hit={hit} />
</>
)
}
return <Hit key={hit.id} hit={hit} />
})}
</HitsList>
{hasMore && (
<Button
Expand Down
15 changes: 15 additions & 0 deletions src/context/ArtistsContext.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React, { createContext, useContext, useState, useMemo } from 'react'

const ArtistsContext = createContext()

export const useArtists = () => useContext(ArtistsContext)

export const ArtistsProvider = ({ children }) => {
const [artists, setArtists] = useState([])

const value = useMemo(() => ({ artists, setArtists }), [artists])

return (
<ArtistsContext.Provider value={value}>{children}</ArtistsContext.Provider>
)
}

0 comments on commit fbc8400

Please sign in to comment.