cozy-ui 117.0.0 → 117.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (27) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/package.json +1 -1
  3. package/react/ActionsMenu/Actions/addToFavorites.js +66 -0
  4. package/react/ActionsMenu/Actions/download.js +42 -0
  5. package/react/ActionsMenu/Actions/index.js +3 -0
  6. package/react/ActionsMenu/Actions/locales/en.json +12 -0
  7. package/react/ActionsMenu/Actions/locales/fr.json +12 -0
  8. package/react/ActionsMenu/Actions/removeFromFavorites.js +66 -0
  9. package/react/NestedSelect/NestedSelect.jsx +23 -12
  10. package/react/NestedSelect/NestedSelect.md +1 -8
  11. package/react/NestedSelect/NestedSelect.spec.jsx +15 -12
  12. package/react/NestedSelect/styles.styl +1 -1
  13. package/react/QualificationModal/helpers.js +61 -0
  14. package/react/QualificationModal/helpers.spec.js +32 -0
  15. package/react/QualificationModal/index.jsx +14 -37
  16. package/react/QualificationModal/locales/en.json +2 -1
  17. package/react/QualificationModal/locales/fr.json +2 -1
  18. package/transpiled/react/ActionsMenu/Actions/addToFavorites.js +144 -0
  19. package/transpiled/react/ActionsMenu/Actions/download.js +49 -0
  20. package/transpiled/react/ActionsMenu/Actions/index.js +3 -0
  21. package/transpiled/react/ActionsMenu/Actions/locales/withActionsLocales.js +24 -0
  22. package/transpiled/react/ActionsMenu/Actions/removeFromFavorites.js +144 -0
  23. package/transpiled/react/NestedSelect/NestedSelect.js +33 -15
  24. package/transpiled/react/QualificationModal/helpers.js +68 -0
  25. package/transpiled/react/QualificationModal/index.js +12 -40
  26. package/transpiled/react/QualificationModal/locales/index.js +4 -2
  27. package/transpiled/react/stylesheet.css +1 -1
package/CHANGELOG.md CHANGED
@@ -1,3 +1,24 @@
1
+ # [117.2.0](https://github.com/cozy/cozy-ui/compare/v117.1.0...v117.2.0) (2025-01-30)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **NestedSelect:** Show now result according to searchResult ([debae36](https://github.com/cozy/cozy-ui/commit/debae36))
7
+
8
+
9
+ ### Features
10
+
11
+ * **NestedSelect:** Add delay on search result ([fc57533](https://github.com/cozy/cozy-ui/commit/fc57533))
12
+ * **NestedSelect:** Replace Input by SearchBar for search options ([cf01651](https://github.com/cozy/cozy-ui/commit/cf01651))
13
+ * **QualificationModal:** Add search bar ([fab5baa](https://github.com/cozy/cozy-ui/commit/fab5baa))
14
+
15
+ # [117.1.0](https://github.com/cozy/cozy-ui/compare/v117.0.0...v117.1.0) (2025-01-21)
16
+
17
+
18
+ ### Features
19
+
20
+ * Add Download and Add/Remove favorites actions ([6e4bca4](https://github.com/cozy/cozy-ui/commit/6e4bca4))
21
+
1
22
  # [117.0.0](https://github.com/cozy/cozy-ui/compare/v116.0.0...v117.0.0) (2025-01-13)
2
23
 
3
24
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-ui",
3
- "version": "117.0.0",
3
+ "version": "117.2.0",
4
4
  "description": "Cozy apps UI SDK",
5
5
  "main": "./index.js",
6
6
  "bin": {
@@ -0,0 +1,66 @@
1
+ import React, { forwardRef } from 'react'
2
+
3
+ import { splitFilename } from 'cozy-client/dist/models/file'
4
+
5
+ import { getActionsI18n } from './locales/withActionsLocales'
6
+ import Icon from '../../Icon'
7
+ import StarOutlineIcon from '../../Icons/StarOutline'
8
+ import ListItemIcon from '../../ListItemIcon'
9
+ import ListItemText from '../../ListItemText'
10
+ import ActionsMenuItem from '../ActionsMenuItem'
11
+
12
+ const makeComponent = (label, icon) => {
13
+ const Component = forwardRef((props, ref) => {
14
+ return (
15
+ <ActionsMenuItem {...props} ref={ref}>
16
+ <ListItemIcon>
17
+ <Icon icon={icon} />
18
+ </ListItemIcon>
19
+ <ListItemText primary={label} />
20
+ </ActionsMenuItem>
21
+ )
22
+ })
23
+
24
+ Component.displayName = 'addToFavorites'
25
+
26
+ return Component
27
+ }
28
+
29
+ export const addToFavorites = ({ showAlert }) => {
30
+ const { t } = getActionsI18n()
31
+ const icon = StarOutlineIcon
32
+ const label = t('favorites.add.label')
33
+
34
+ return {
35
+ name: 'addToFavorites',
36
+ icon,
37
+ label,
38
+ displayCondition: docs =>
39
+ docs.length > 0 && docs.every(doc => !doc.cozyMetadata?.favorite),
40
+ Component: makeComponent(label, icon),
41
+ action: async (docs, { client }) => {
42
+ try {
43
+ for (const doc of docs) {
44
+ await client.save({
45
+ ...doc,
46
+ cozyMetadata: {
47
+ ...doc.cozyMetadata,
48
+ favorite: true
49
+ }
50
+ })
51
+ }
52
+
53
+ const { filename } = splitFilename(docs[0])
54
+ showAlert({
55
+ message: t('favorites.add.success', {
56
+ filename,
57
+ smart_count: docs.length
58
+ }),
59
+ severity: 'success'
60
+ })
61
+ } catch (error) {
62
+ showAlert({ message: t('favorites.error'), severity: 'error' })
63
+ }
64
+ }
65
+ }
66
+ }
@@ -0,0 +1,42 @@
1
+ import React, { forwardRef } from 'react'
2
+
3
+ import { downloadFile } from 'cozy-client/dist/models/file'
4
+
5
+ import { getActionsI18n } from './locales/withActionsLocales'
6
+ import Icon from '../../Icon'
7
+ import DownloadIcon from '../../Icons/Download'
8
+ import ListItemIcon from '../../ListItemIcon'
9
+ import ListItemText from '../../ListItemText'
10
+ import ActionsMenuItem from '../ActionsMenuItem'
11
+
12
+ const makeComponent = (label, icon) => {
13
+ const Component = forwardRef((props, ref) => {
14
+ return (
15
+ <ActionsMenuItem {...props} ref={ref}>
16
+ <ListItemIcon>
17
+ <Icon icon={icon} />
18
+ </ListItemIcon>
19
+ <ListItemText primary={label} />
20
+ </ActionsMenuItem>
21
+ )
22
+ })
23
+
24
+ Component.displayName = 'download'
25
+
26
+ return Component
27
+ }
28
+
29
+ export const download = ({ encryptedUrl }) => {
30
+ const { t } = getActionsI18n()
31
+ const icon = DownloadIcon
32
+ const label = t('download')
33
+
34
+ return {
35
+ name: 'download',
36
+ icon,
37
+ label,
38
+ Component: makeComponent(label, icon),
39
+ action: (docs, { client, webviewIntent }) =>
40
+ downloadFile({ client, file: docs[0], url: encryptedUrl, webviewIntent })
41
+ }
42
+ }
@@ -5,6 +5,9 @@ export { smsTo } from './smsTo'
5
5
  export { call } from './call'
6
6
  export { emailTo } from './emailTo'
7
7
  export { print } from './print'
8
+ export { download } from './download'
9
+ export { addToFavorites } from './addToFavorites'
10
+ export { removeFromFavorites } from './removeFromFavorites'
8
11
  export { viewInContacts } from './viewInContacts'
9
12
  export { viewInDrive } from './viewInDrive'
10
13
  export { copyToClipboard } from './copyToClipboard'
@@ -5,6 +5,18 @@
5
5
  "emailTo": "Send an email",
6
6
  "smsTo": "Send a message",
7
7
  "print": "Print",
8
+ "download": "Download",
9
+ "favorites": {
10
+ "add": {
11
+ "label": "Add to favorites",
12
+ "success": "%{filename} has been added to favorites |||| These items have been added to favorites"
13
+ },
14
+ "remove": {
15
+ "label": "Remove from favorites",
16
+ "success": "%{filename} has been removed from favorites |||| These items have been removed from favorites"
17
+ },
18
+ "error": "An error occurred, please try again."
19
+ },
8
20
  "others": "Others",
9
21
  "editAttribute": "Edit attribute",
10
22
  "copyToClipboard": {
@@ -5,6 +5,18 @@
5
5
  "emailTo": "Envoyer un e-mail",
6
6
  "smsTo": "Envoyer un message",
7
7
  "print": "Imprimer",
8
+ "download": "Télécharger",
9
+ "favorites": {
10
+ "add": {
11
+ "label": "Ajouter aux favoris",
12
+ "success": "%{filename} a été ajouté aux favoris |||| Ces éléments ont été ajoutés aux favoris"
13
+ },
14
+ "remove": {
15
+ "label": "Retirer des favoris",
16
+ "success": "%{filename} a été retiré des favoris |||| Ces éléments ont été retirés des favoris"
17
+ },
18
+ "error": "Une erreur est survenue, merci de réessayer."
19
+ },
8
20
  "others": "Autres",
9
21
  "editAttribute": "Editer l'attribut",
10
22
  "copyToClipboard": {
@@ -0,0 +1,66 @@
1
+ import React, { forwardRef } from 'react'
2
+
3
+ import { splitFilename } from 'cozy-client/dist/models/file'
4
+
5
+ import { getActionsI18n } from './locales/withActionsLocales'
6
+ import Icon from '../../Icon'
7
+ import StarIcon from '../../Icons/Star'
8
+ import ListItemIcon from '../../ListItemIcon'
9
+ import ListItemText from '../../ListItemText'
10
+ import ActionsMenuItem from '../ActionsMenuItem'
11
+
12
+ const makeComponent = (label, icon) => {
13
+ const Component = forwardRef((props, ref) => {
14
+ return (
15
+ <ActionsMenuItem {...props} ref={ref}>
16
+ <ListItemIcon>
17
+ <Icon icon={icon} />
18
+ </ListItemIcon>
19
+ <ListItemText primary={label} />
20
+ </ActionsMenuItem>
21
+ )
22
+ })
23
+
24
+ Component.displayName = 'removeFromFavorites'
25
+
26
+ return Component
27
+ }
28
+
29
+ export const removeFromFavorites = ({ showAlert }) => {
30
+ const { t } = getActionsI18n()
31
+ const icon = StarIcon
32
+ const label = t('favorites.remove.label')
33
+
34
+ return {
35
+ name: 'removeFromFavorites',
36
+ icon,
37
+ label,
38
+ displayCondition: docs =>
39
+ docs.length > 0 && docs.every(doc => doc.cozyMetadata?.favorite),
40
+ Component: makeComponent(label, icon),
41
+ action: async (docs, { client }) => {
42
+ try {
43
+ for (const doc of docs) {
44
+ await client.save({
45
+ ...doc,
46
+ cozyMetadata: {
47
+ ...doc.cozyMetadata,
48
+ favorite: false
49
+ }
50
+ })
51
+ }
52
+
53
+ const { filename } = splitFilename(docs[0])
54
+ showAlert({
55
+ message: t('favorites.success.remove', {
56
+ filename,
57
+ smart_count: docs.length
58
+ }),
59
+ severity: 'success'
60
+ })
61
+ } catch (error) {
62
+ showAlert({ message: t('favorites.error'), severity: 'error' })
63
+ }
64
+ }
65
+ }
66
+ }
@@ -1,13 +1,14 @@
1
1
  import cx from 'classnames'
2
+ import debounce from 'lodash/debounce'
2
3
  import omit from 'lodash/omit'
3
4
  import PropTypes from 'prop-types'
4
- import React, { useState, useRef } from 'react'
5
+ import React, { useState, useRef, useMemo } from 'react'
5
6
 
6
7
  import ItemRow from './ItemRow'
7
8
  import { makeHistory } from './helpers'
8
9
  import styles from './styles.styl'
9
- import Input from '../Input'
10
10
  import List from '../List'
11
+ import SearchBar from '../SearchBar'
11
12
  import Typography from '../Typography'
12
13
 
13
14
  export { ItemRow }
@@ -35,9 +36,13 @@ const NestedSelect = ({
35
36
  const innerRef = useRef()
36
37
  const [state, setState] = useState({
37
38
  history: makeHistory(options, canSelectParent),
38
- searchValue: '',
39
- searchResult: []
39
+ searchValue: ''
40
40
  })
41
+ const [searchResult, setSearchResult] = useState(null)
42
+ const delayedSetSearchResult = useMemo(
43
+ () => debounce(setSearchResult, 250),
44
+ [setSearchResult]
45
+ )
41
46
 
42
47
  const handleBack = () => {
43
48
  const [item, ...newHistory] = state.history
@@ -70,16 +75,21 @@ const NestedSelect = ({
70
75
  if (onSearch) {
71
76
  const searchValue = ev.target.value
72
77
  const searchResult = onSearch(searchValue)
73
- setState(state => ({ ...state, searchValue, searchResult }))
78
+ setState(state => ({ ...state, searchValue }))
79
+ delayedSetSearchResult(searchResult)
74
80
  }
75
81
  }
76
82
 
83
+ const onClear = () => {
84
+ setState(state => ({ ...state, searchValue: '' }))
85
+ delayedSetSearchResult(null)
86
+ }
87
+
77
88
  const current = state.history[0]
78
89
  const children = current.children || []
79
90
  const level = state.history.length - 1
80
91
  const parentItem = transformParentItem(omit(current, 'children'))
81
92
 
82
- const hasSearchResult = state.searchValue?.length > 0
83
93
  const isSelectedWithLevel = item => isSelected(item, level)
84
94
  const currentTitle = current.title || title
85
95
 
@@ -117,16 +127,17 @@ const NestedSelect = ({
117
127
  [styles['search-container--without-title']]: !currentTitle
118
128
  })}
119
129
  >
120
- <Input
130
+ <SearchBar
121
131
  placeholder={searchOptions.placeholderSearch}
122
- onChange={onChange}
123
132
  value={state.searchValue}
133
+ onChange={onChange}
134
+ onClear={onClear}
124
135
  />
125
136
  </div>
126
137
  )}
127
138
 
128
- {hasSearchResult ? (
129
- state.searchResult.length === 0 ? (
139
+ {searchResult ? (
140
+ searchResult.length === 0 ? (
130
141
  <Typography
131
142
  variant="body1"
132
143
  className="u-flex u-flex-justify-center u-mb-1 "
@@ -134,14 +145,14 @@ const NestedSelect = ({
134
145
  {searchOptions.noDataLabel}
135
146
  </Typography>
136
147
  ) : (
137
- state.searchResult.map((item, index) => (
148
+ searchResult.map((item, index) => (
138
149
  <ItemRow
139
150
  radioPosition={radioPosition}
140
151
  key={item.key || item.title}
141
152
  item={item}
142
153
  onClick={handleClickItem}
143
154
  isSelected={isSelectedWithLevel(item)}
144
- isLast={index === state.searchResult.length - 1}
155
+ isLast={index === searchResult.length - 1}
145
156
  ellipsis={ellipsis}
146
157
  noDivider={noDivider}
147
158
  />
@@ -155,14 +155,7 @@ const InteractiveExample = () => {
155
155
  onSearch: (value) => {
156
156
  const options = makeOptions({ withHeaders })
157
157
  return options.children.filter(o => o.description && o.description.toLowerCase().includes(value.toLowerCase()))
158
- },
159
- displaySearchResultItem: item =>
160
- <ListItem key={item.id} dense button divider>
161
- <ListItemText
162
- primary={item.description}
163
- ellipsis
164
- />
165
- </ListItem>
158
+ }
166
159
  })
167
160
 
168
161
  const handleSelect = item => {
@@ -1,9 +1,9 @@
1
1
  import React from 'react'
2
2
  import '@testing-library/jest-dom'
3
- import { render, fireEvent } from '@testing-library/react'
3
+ import { render, fireEvent, waitFor } from '@testing-library/react'
4
4
 
5
5
  import NestedSelect from './NestedSelect'
6
- import { BreakpointsProvider } from '../providers/Breakpoints'
6
+ import DemoProvider from '../providers/DemoProvider'
7
7
 
8
8
  describe('NestedSelect', () => {
9
9
  const makeOption = text => ({
@@ -40,7 +40,7 @@ describe('NestedSelect', () => {
40
40
  const options = makeOptions(itemSelected)
41
41
 
42
42
  return render(
43
- <BreakpointsProvider>
43
+ <DemoProvider>
44
44
  <NestedSelect
45
45
  canSelectParent={canSelectParent}
46
46
  options={options}
@@ -49,7 +49,7 @@ describe('NestedSelect', () => {
49
49
  onCancel={onCancel}
50
50
  searchOptions={searchOptions}
51
51
  />
52
- </BreakpointsProvider>
52
+ </DemoProvider>
53
53
  )
54
54
  }
55
55
 
@@ -159,9 +159,11 @@ describe('NestedSelect', () => {
159
159
  const searchInput = getByPlaceholderText('Placeholder Search')
160
160
  expect(searchInput).toBeTruthy()
161
161
 
162
- fireEvent.change(searchInput, { target: { value: 'cozy' } })
163
- const noData = getByText('No Data Found')
164
- expect(noData).toBeTruthy()
162
+ waitFor(() => {
163
+ fireEvent.change(searchInput, { target: { value: 'cozy' } })
164
+ const noData = getByText('No Data Found')
165
+ expect(noData).toBeTruthy()
166
+ })
165
167
  })
166
168
 
167
169
  it('should show search results', () => {
@@ -186,11 +188,12 @@ describe('NestedSelect', () => {
186
188
  const searchInput = getByPlaceholderText('Placeholder Search')
187
189
  expect(searchInput).toBeTruthy()
188
190
 
189
- fireEvent.change(searchInput, { target: { value: 'cozy' } })
190
-
191
- expect(queryByText('cozy 1')).toBeTruthy()
192
- expect(queryByText('cozy 1')).toBeTruthy()
193
- expect(queryByText('anything')).toBeFalsy()
191
+ waitFor(() => {
192
+ fireEvent.change(searchInput, { target: { value: 'cozy' } })
193
+ expect(queryByText('cozy 1')).toBeTruthy()
194
+ expect(queryByText('cozy 1')).toBeTruthy()
195
+ expect(queryByText('anything')).toBeFalsy()
196
+ })
194
197
  })
195
198
  })
196
199
  })
@@ -13,5 +13,5 @@
13
13
  top -0.5rem
14
14
 
15
15
  .search-container--without-title
16
- margin-right 5rem
16
+ margin-right 1rem
17
17
  margin-top 0.5rem
@@ -0,0 +1,61 @@
1
+ import React from 'react'
2
+
3
+ import { themesList } from 'cozy-client/dist/models/document/documentTypeData'
4
+ import { isQualificationNote } from 'cozy-client/dist/models/document/documentTypeDataHelpers'
5
+ import { getBoundT } from 'cozy-client/dist/models/document/locales'
6
+
7
+ import Icon from '../Icon'
8
+ import FileTypeNoteIcon from '../Icons/FileTypeNote'
9
+ import QualificationIconStack from '../QualificationIconStack'
10
+
11
+ export const makeOptions = lang => {
12
+ const qualifT = getBoundT(lang)
13
+
14
+ return {
15
+ children: [
16
+ {
17
+ id: 'none',
18
+ title: qualifT('Scan.themes.none'),
19
+ icon: <QualificationIconStack />
20
+ },
21
+ ...themesList.map(theme => ({
22
+ id: theme.id,
23
+ title: qualifT(`Scan.themes.${theme.label}`),
24
+ icon: <QualificationIconStack theme={theme.label} />,
25
+ children: theme.items.map(item => ({
26
+ id: item.label,
27
+ item,
28
+ title: qualifT(`Scan.items.${item.label}`),
29
+ icon: isQualificationNote(item) ? (
30
+ <Icon icon={FileTypeNoteIcon} size={64} />
31
+ ) : (
32
+ <QualificationIconStack qualification={item.label} />
33
+ )
34
+ }))
35
+ }))
36
+ ]
37
+ }
38
+ }
39
+
40
+ export const searchOptionsFn = (options, value) => {
41
+ const deepOptions = options.children
42
+ .flatMap(child => child.children)
43
+ .reduce((acc, curr) => {
44
+ if (!!curr && !acc.some(el => el.id === curr.id)) {
45
+ acc.push(curr)
46
+ }
47
+ return acc
48
+ }, [])
49
+
50
+ return deepOptions.filter(deepOption =>
51
+ deepOption.title.toLowerCase().includes(value.toLowerCase())
52
+ )
53
+ }
54
+
55
+ export const makeSearchOptions = ({ options, title, noDataLabel, t }) => {
56
+ return {
57
+ placeholderSearch: title || t('QualificationModal.title'),
58
+ noDataLabel: noDataLabel || t('QualificationModal.noDataLabel'),
59
+ onSearch: value => searchOptionsFn(options, value)
60
+ }
61
+ }
@@ -0,0 +1,32 @@
1
+ import { searchOptionsFn } from './helpers'
2
+
3
+ describe('searchOptionsFn', () => {
4
+ it('should return only the uniq good result', () => {
5
+ const options = {
6
+ children: [
7
+ { id: 'none', title: 'None' },
8
+ {
9
+ id: 'theme1',
10
+ title: 'Identity',
11
+ children: [
12
+ { id: '01', title: 'Identity Photo' },
13
+ { id: '02', title: 'ID card' }
14
+ ]
15
+ },
16
+ {
17
+ id: 'theme2',
18
+ title: 'Family',
19
+ children: [
20
+ { id: '03', title: 'Family record book' },
21
+ { id: '04', title: 'Birth certificate' },
22
+ { id: '01', title: 'Identity Photo' }
23
+ ]
24
+ }
25
+ ]
26
+ }
27
+
28
+ const res = searchOptionsFn(options, 'photo')
29
+
30
+ expect(res).toStrictEqual([{ id: '01', title: 'Identity Photo' }])
31
+ })
32
+ })
@@ -2,54 +2,30 @@ import PropTypes from 'prop-types'
2
2
  import React, { useMemo } from 'react'
3
3
 
4
4
  import { useClient } from 'cozy-client'
5
- import { themesList } from 'cozy-client/dist/models/document/documentTypeData'
6
- import { isQualificationNote } from 'cozy-client/dist/models/document/documentTypeDataHelpers'
7
- import { getBoundT } from 'cozy-client/dist/models/document/locales'
8
5
  import { isSupportedQualification } from 'cozy-client/dist/models/document/qualification'
9
6
 
7
+ import { makeOptions, makeSearchOptions } from './helpers'
10
8
  import { locales } from './locales'
11
- import Icon from '../Icon'
12
- import FileTypeNoteIcon from '../Icons/FileTypeNote'
13
9
  import NestedSelectResponsive from '../NestedSelect/NestedSelectResponsive'
14
- import QualificationIconStack from '../QualificationIconStack'
15
10
  import { useI18n, useExtendI18n } from '../providers/I18n'
16
11
 
17
- const makeOptions = lang => {
18
- const qualifT = getBoundT(lang)
19
-
20
- return {
21
- children: [
22
- {
23
- id: 'none',
24
- title: qualifT('Scan.themes.none'),
25
- icon: <QualificationIconStack />
26
- },
27
- ...themesList.map(theme => ({
28
- id: theme.id,
29
- title: qualifT(`Scan.themes.${theme.label}`),
30
- icon: <QualificationIconStack theme={theme.label} />,
31
- children: theme.items.map(item => ({
32
- id: item.label,
33
- item,
34
- title: qualifT(`Scan.items.${item.label}`),
35
- icon: isQualificationNote(item) ? (
36
- <Icon icon={FileTypeNoteIcon} size={64} />
37
- ) : (
38
- <QualificationIconStack qualification={item.label} />
39
- )
40
- }))
41
- }))
42
- ]
43
- }
44
- }
45
-
46
- const QualificationModal = ({ file, title, onClose }) => {
12
+ const QualificationModal = ({ file, title, noDataLabel, onClose }) => {
47
13
  useExtendI18n(locales)
48
14
  const client = useClient()
49
15
  const { t, lang } = useI18n()
50
16
 
51
17
  const qualificationLabel = file.metadata?.qualification?.label
52
18
  const options = useMemo(() => makeOptions(lang), [lang])
19
+ const searchOptions = useMemo(
20
+ () =>
21
+ makeSearchOptions({
22
+ options,
23
+ title,
24
+ noDataLabel,
25
+ t
26
+ }),
27
+ [options, title, noDataLabel, t]
28
+ )
53
29
 
54
30
  const isSelected = ({ id, item }) => {
55
31
  return isSupportedQualification(qualificationLabel)
@@ -74,11 +50,11 @@ const QualificationModal = ({ file, title, onClose }) => {
74
50
 
75
51
  return (
76
52
  <NestedSelectResponsive
77
- title={title || t('QualificationModal.title')}
78
53
  options={options}
79
54
  noDivider
80
55
  document={file}
81
56
  isSelected={isSelected}
57
+ searchOptions={searchOptions}
82
58
  onSelect={handleClick}
83
59
  onClose={onClose}
84
60
  />
@@ -88,6 +64,7 @@ const QualificationModal = ({ file, title, onClose }) => {
88
64
  QualificationModal.propTypes = {
89
65
  file: PropTypes.object,
90
66
  title: PropTypes.string,
67
+ noDataLabel: PropTypes.string,
91
68
  onClose: PropTypes.func
92
69
  }
93
70
 
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "QualificationModal": {
3
- "title": "Document type"
3
+ "title": "Document type",
4
+ "noDataLabel": "No result"
4
5
  }
5
6
  }
@@ -1,5 +1,6 @@
1
1
  {
2
2
  "QualificationModal": {
3
- "title": "Type de document"
3
+ "title": "Type de document",
4
+ "noDataLabel": "Aucun résultat"
4
5
  }
5
6
  }