Skip to content

Commit

Permalink
Merge pull request #696 from cozy/improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
ptbrowne authored Oct 15, 2020
2 parents 3b01ecf + cc9b5b3 commit d5a5b9a
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 75 deletions.
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"version": "1.9.3",
"main": "src/index.jsx",
"scripts": {
"deploy": "env HUSKY_SKIP_HOOKS=1 git-directory-deploy --directory build/ --branch=${DEPLOY_BRANCH:-build} --repo=${DEPLOY_REPOSITORY:-origin}",
"tx": "tx pull --all",
"lint": "yarn lint:js && yarn lint:styles",
"lint:js": "eslint '{src,test}/**/*.{js,jsx}'",
Expand Down
76 changes: 9 additions & 67 deletions src/ducks/apps/components/Sections/Sections.jsx
Original file line number Diff line number Diff line change
@@ -1,76 +1,15 @@
import React, { Component, useCallback, useMemo } from 'react'
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import Fuse from 'fuse.js'
import sortBy from 'lodash/sortBy'
import debounce from 'lodash/debounce'

import Input from 'cozy-ui/transpiled/react/Input'
import InputGroup from 'cozy-ui/transpiled/react/InputGroup'
import Label from 'cozy-ui/transpiled/react/Label'
import Icon from 'cozy-ui/transpiled/react/Icon'
import { translate, useI18n } from 'cozy-ui/transpiled/react/I18n'
import useBreakpoints from 'cozy-ui/transpiled/react/hooks/useBreakpoints'
import { translate } from 'cozy-ui/transpiled/react/I18n'
import AppSections from 'cozy-ui/transpiled/react/AppSections'
import * as filterUtils from 'cozy-ui/transpiled/react/AppSections/search'

import flag from 'cozy-flags'
import StoreAppItem from './components/StoreAppItem'

const SearchField = ({ onChange, value }) => {
const { t } = useI18n()
const { isMobile } = useBreakpoints()
const handleChange = useCallback(
ev => {
onChange(ev.target.value)
},
[onChange]
)
return (
<>
{!isMobile ? (
<Label className="u-di u-mr-half" htmlFor="discover-search">
{t('discover-search-field.label')}
</Label>
) : null}
<InputGroup
className={isMobile ? '' : 'u-mb-1'}
prepend={
isMobile ? (
<Icon icon="magnifier" className="u-pl-1 u-coolGrey" />
) : null
}
>
<Input
id="discover-search"
placeholder={t('discover-search-field.placeholder')}
onChange={handleChange}
type="text"
value={value}
/>
</InputGroup>
</>
)
}

const SearchResults = ({ searchResults, onAppClick }) => {
const sortedSortResults = useMemo(() => {
return sortBy(searchResults, result => result.score)
}, [searchResults])
return (
<div className="u-mv-1 u-flex u-flex-wrap">
{sortedSortResults.map(result => {
const app = result.item
return (
<StoreAppItem
onClick={() => onAppClick(app.slug)}
key={app.slug}
app={app}
/>
)
})}
</div>
)
}
import { SearchField, SearchResults } from 'ducks/search/components'

/**
* Shows a list of apps grouped by categories.
Expand Down Expand Up @@ -109,12 +48,15 @@ export class Sections extends Component {
const { lang } = this.props
const options = {
includeScore: true,
includeMatches: true,
minMatchCharLength: 3,
threshold: 0.2,
ignoreLocation: true,
keys: [
'name',
{ name: 'name', weight: 3 },
'categories',
`locales.${lang}.short_description`,
`locales.${lang}.long_description`,
'doctypes'
`locales.${lang}.long_description`
]
}

Expand Down
2 changes: 1 addition & 1 deletion src/ducks/apps/components/Sections/index.spec.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ describe('Search', () => {
expect(() => root.getByText('Bouilligue')).not.toThrow()

act(() => {
fireEvent.change(input, { target: { value: 'trn' } })
fireEvent.change(input, { target: { value: 'tri' } })
})

expect(() => root.getByText('Trinlane')).not.toThrow()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,17 @@
import React from 'react'
import useBreakpoints from 'cozy-ui/transpiled/react/hooks/useBreakpoints'
import { useI18n } from 'cozy-ui/transpiled/react/I18n'
import AppTile from 'cozy-ui/transpiled/react/AppTile'

import { getTranslatedManifestProperty } from '../helpers'
import { getTranslatedManifestProperty } from './helpers'

const StoreAppItem = ({ app, onClick }) => {
const { isMobile } = useBreakpoints()
const { t } = useI18n()
return (
<AppTile
app={app}
namePrefix={getTranslatedManifestProperty(app, 'name_prefix', t)}
name={getTranslatedManifestProperty(app, 'name', t)}
onClick={onClick}
isMobile={isMobile}
/>
)
}
Expand Down
File renamed without changes.
File renamed without changes.
85 changes: 85 additions & 0 deletions src/ducks/search/components.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React, { useCallback, useMemo } from 'react'
import sortBy from 'lodash/sortBy'

import Icon from 'cozy-ui/transpiled/react/Icon'
import Label from 'cozy-ui/transpiled/react/Label'
import { useI18n } from 'cozy-ui/transpiled/react/I18n'
import useBreakpoints from 'cozy-ui/transpiled/react/hooks/useBreakpoints'
import InputGroup from 'cozy-ui/transpiled/react/InputGroup'
import Input from 'cozy-ui/transpiled/react/Input'

import flag from 'cozy-flags'

import StoreAppItem from 'ducks/apps/components/StoreAppItem'

import { dumpMatches } from 'ducks/search/utils'

export const SearchField = ({ onChange, value }) => {
const { t } = useI18n()
const { isMobile } = useBreakpoints()
const handleChange = useCallback(
ev => {
onChange(ev.target.value)
},
[onChange]
)
return (
<>
{!isMobile ? (
<Label className="u-di u-mr-half" htmlFor="discover-search">
{t('discover-search-field.label')}
</Label>
) : null}
<InputGroup
className={isMobile ? '' : 'u-mb-1'}
prepend={
isMobile ? (
<Icon icon="magnifier" className="u-pl-1 u-coolGrey" />
) : null
}
>
<Input
id="discover-search"
placeholder={t('discover-search-field.placeholder')}
onChange={handleChange}
type="text"
value={value}
/>
</InputGroup>
</>
)
}

export const SearchResults = ({ searchResults, onAppClick }) => {
const sortedSortResults = useMemo(() => {
return sortBy(searchResults, result => result.score)
}, [searchResults])
return (
<div className="u-mv-1 u-flex u-flex-wrap">
{sortedSortResults.map(result => {
const app = result.item
return flag('store.show-search-score') ? (
<div>
<StoreAppItem
onClick={() => onAppClick(app.slug)}
key={app.slug}
app={app}
/>
<small
onClick={() => dumpMatches(result)}
title={JSON.stringify(result.matches, null, 2)}
>
{result.score.toFixed(2)}
</small>
</div>
) : (
<StoreAppItem
onClick={() => onAppClick(app.slug)}
key={app.slug}
app={app}
/>
)
})}
</div>
)
}
40 changes: 40 additions & 0 deletions src/ducks/search/utils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Given a list of intervals, will return all the intervals
* along with the implicit intervals that are between the original
* intervals. If the interval was in the original input, it will
* be returned with { mark: true}, else if it is an implied
* interval, it will be returned with { mark: false }.
*/
export const fillIntervals = (intervals, maxIndex) => {
let cur = 0
let res = []
for (let idx of intervals) {
if (idx[0] != cur) {
res.push({ idx: [cur, idx[0]], mark: false })
}
res.push({ idx, mark: true })
cur = idx[1]
}
if (cur != maxIndex) {
res.push({ idx: [cur, maxIndex], mark: false })
}

return res
}

/** Dumps a fuse.js in the console and will highlight the part that matched */
export const dumpMatches = result => {
for (let m of result.matches) {
const allindices = fillIntervals(m.indices, m.value.length)
// eslint-disable-next-line no-console
console.log(
allindices
.map(o => {
const [start, end] = o.idx
const substr = m.value.substring(start, end)
return o.mark ? `**${substr}**` : substr
})
.join('')
)
}
}
13 changes: 13 additions & 0 deletions src/ducks/search/utils.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { fillIntervals } from './utils'

test('fillIntervals', () => {
expect(fillIntervals([[1, 2], [4, 5], [9, 12]], 15)).toEqual([
{ idx: [0, 1], mark: false },
{ idx: [1, 2], mark: true },
{ idx: [2, 4], mark: false },
{ idx: [4, 5], mark: true },
{ idx: [5, 9], mark: false },
{ idx: [9, 12], mark: true },
{ idx: [12, 15], mark: false }
])
})
6 changes: 3 additions & 3 deletions src/lib/helpers.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import _get from 'lodash.get'
import get from 'lodash/get'

export const getTranslatedManifestProperty = (app, path, t) => {
if (!t || !app || !path) return _get(app, path, '')
if (!t || !app || !path) return get(app, path, '')
return t(`apps.${app.slug}.${path}`, {
_: _get(app, path, '')
_: get(app, path, '')
})
}

Expand Down

0 comments on commit d5a5b9a

Please sign in to comment.