Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: add debounced data-element search #88

Draft
wants to merge 3 commits into
base: development
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import i18n from '@dhis2/d2-i18n'
import { InputField } from '@dhis2/ui'
import PropTypes from 'prop-types'
import React, { useEffect, useState } from 'react'
import useDebounce from './use-debounce.js'
import { useDebounce } from '../../shared/index.js'

export default function DebouncedSearchInput({ onChange, initialValue }) {
const [value, setValue] = useState(initialValue)
Expand Down
3 changes: 1 addition & 2 deletions src/data-workspace/entry-form.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ export const EntryForm = ({ dataSet }) => {
<>
{formType !== FORM_TYPES.CUSTOM && (
<FilterField
value={globalFilterText}
setFilterText={setGlobalFilterText}
onFilterChange={setGlobalFilterText}
formType={formType}
/>
)}
Expand Down
14 changes: 9 additions & 5 deletions src/data-workspace/filter-field.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,17 @@ import i18n from '@dhis2/d2-i18n'
import { Button, InputField } from '@dhis2/ui'
import classNames from 'classnames'
import PropTypes from 'prop-types'
import React from 'react'
import React, { useState } from 'react'
import { useDebounceCallback } from '../shared/index.js'
import { FORM_TYPES } from './constants.js'
import styles from './entry-form.module.css'

export default function FilterField({ value, setFilterText, formType }) {
export default function FilterField({ onFilterChange, formType }) {
const [filterText, setFilterText] = useState('')
const wrapperClasses = classNames(styles.filterWrapper, 'hide-for-print')

useDebounceCallback(filterText, onFilterChange)

return (
<div className={wrapperClasses}>
<InputField
Expand All @@ -19,7 +24,7 @@ export default function FilterField({ value, setFilterText, formType }) {
? i18n.t('Filter fields in all sections')
: i18n.t('Filter fields')
}
value={value}
value={filterText}
onChange={({ value }) => setFilterText(value)}
/>
<Button
Expand All @@ -36,6 +41,5 @@ export default function FilterField({ value, setFilterText, formType }) {

FilterField.propTypes = {
formType: PropTypes.string,
setFilterText: PropTypes.func,
value: PropTypes.string,
onFilterChange: PropTypes.func,
}
32 changes: 32 additions & 0 deletions src/data-workspace/section-form/section-filter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import i18n from '@dhis2/d2-i18n'
import { colors, IconFilter16 } from '@dhis2/ui'
import PropTypes from 'prop-types'
import React, { useState } from 'react'
import { useDebounceCallback } from '../../shared/index.js'
import styles from './section.module.css'

export const SectionFilter = ({ id, onFilterChange }) => {
const [filterText, setFilterText] = useState('')

useDebounceCallback(filterText, onFilterChange)

return (
<label htmlFor={id} className={styles.filterWrapper}>
<IconFilter16 color={colors.grey600} />
<input
name={id}
id={id}
type="text"
placeholder={i18n.t('Type here to filter in this section')}
value={filterText}
onChange={({ target }) => setFilterText(target.value)}
className={styles.filterInput}
/>
</label>
)
}

SectionFilter.propTypes = {
id: PropTypes.string,
onFilterChange: PropTypes.func,
}
34 changes: 6 additions & 28 deletions src/data-workspace/section-form/section.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
import i18n from '@dhis2/d2-i18n'
import {
colors,
IconFilter16,
Table,
TableCellHead,
TableHead,
TableRowHead,
} from '@dhis2/ui'
import { Table, TableCellHead, TableHead, TableRowHead } from '@dhis2/ui'
import classNames from 'classnames'
import PropTypes from 'prop-types'
import React, { useState } from 'react'
import { useMetadata, selectors } from '../../metadata/index.js'
import { CategoryComboTable } from '../category-combo-table/index.js'
import { getFieldId } from '../get-field-id.js'
import { SectionFilter } from './section-filter.js'
import styles from './section.module.css'

export const SectionFormSection = ({
Expand Down Expand Up @@ -75,25 +68,10 @@ export const SectionFormSection = ({
</TableRowHead>
<TableRowHead>
<TableCellHead colSpan="100%" className={headerCellStyles}>
<label
htmlFor={filterInputId}
className={styles.filterWrapper}
>
<IconFilter16 color={colors.grey600} />
<input
name={filterInputId}
id={filterInputId}
type="text"
placeholder={i18n.t(
'Type here to filter in this section'
)}
value={filterText}
onChange={({ target }) =>
setFilterText(target.value)
}
className={styles.filterInput}
/>
</label>
<SectionFilter
id={filterInputId}
onFilterChange={setFilterText}
/>
</TableCellHead>
</TableRowHead>
</TableHead>
Expand Down
1 change: 1 addition & 0 deletions src/shared/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,4 @@ export * from './fixed-periods/index.js'
export * from './period/index.js'
export * from './sidebar/index.js'
export * from './utils.js'
export * from './use-debounce.js'
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useEffect, useState } from 'react'

/** Copied from https://usehooks.com/useDebounce/ */
export default function useDebounce(value, delay) {
export function useDebounce(value, delay) {
const [debouncedValue, setDebouncedValue] = useState(value)

useEffect(() => {
Expand All @@ -11,3 +11,11 @@ export default function useDebounce(value, delay) {

return debouncedValue
}

export function useDebounceCallback(value, cb, delay = 200) {
const debouncedValue = useDebounce(value, delay)

useEffect(() => {
cb(debouncedValue)
}, [debouncedValue, cb])
}