@centreon/ui 23.10.95 → 23.10.97

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@centreon/ui",
3
- "version": "23.10.95",
3
+ "version": "23.10.97",
4
4
  "description": "Centreon UI Components",
5
5
  "scripts": {
6
6
  "eslint": "eslint ./src --ext .js,.jsx,.ts,.tsx --max-warnings 0",
@@ -107,7 +107,7 @@
107
107
  "@lexical/rich-text": "^0.11.3",
108
108
  "@lexical/selection": "0.11.3",
109
109
  "@lexical/utils": "0.11.3",
110
- "@react-spring/web": "9.6.0",
110
+ "@react-spring/web": "^9.7.3",
111
111
  "@visx/curve": "^2.1.0",
112
112
  "@visx/group": "^3.3.0",
113
113
  "@visx/pattern": "^3.0.0",
@@ -2,12 +2,8 @@ import { makeStyles } from 'tss-react/mui';
2
2
  import { T, always, cond, equals } from 'ramda';
3
3
 
4
4
  import { SvgIconComponent } from '@mui/icons-material';
5
- import {
6
- FormControlLabel,
7
- Checkbox as MuiCheckbox,
8
- Box,
9
- Typography
10
- } from '@mui/material';
5
+ import Typography, { TypographyTypeMap } from '@mui/material/Typography';
6
+ import { FormControlLabel, Checkbox as MuiCheckbox, Box } from '@mui/material';
11
7
 
12
8
  export type LabelPlacement = 'bottom' | 'top' | 'end' | 'start' | undefined;
13
9
 
@@ -60,6 +56,7 @@ interface Props {
60
56
  disabled?: boolean;
61
57
  label: string;
62
58
  labelPlacement?: LabelPlacement;
59
+ labelProps?: TypographyTypeMap['props'];
63
60
  onChange?: (e) => void;
64
61
  }
65
62
 
@@ -71,7 +68,8 @@ const Checkbox = ({
71
68
  className,
72
69
  disabled = false,
73
70
  labelPlacement = 'end',
74
- dataTestId
71
+ dataTestId,
72
+ labelProps
75
73
  }: Props): JSX.Element => {
76
74
  const { classes, cx } = useStyles({
77
75
  hasIcon: !!Icon,
@@ -96,7 +94,11 @@ const Checkbox = ({
96
94
  }
97
95
  data-testid={dataTestId || ''}
98
96
  key={label}
99
- label={<Typography className={classes.label}>{label}</Typography>}
97
+ label={
98
+ <Typography classes={{ root: classes.label }} {...labelProps}>
99
+ {label}
100
+ </Typography>
101
+ }
100
102
  labelPlacement={labelPlacement}
101
103
  sx={{ margin: 0, padding: 0 }}
102
104
  />
@@ -1,15 +1,19 @@
1
1
  import { equals, includes } from 'ramda';
2
2
  import { makeStyles } from 'tss-react/mui';
3
3
 
4
- import { FormGroup } from '@mui/material';
4
+ import FormGroup, { FormGroupProps } from '@mui/material/FormGroup';
5
+ import { TypographyTypeMap } from '@mui/material/Typography';
5
6
 
6
7
  import Checkbox, { LabelPlacement } from '../Checkbox';
7
8
 
8
9
  interface Props {
10
+ className?: string;
9
11
  dataTestId?: string;
10
12
  direction?: 'horizontal' | 'vertical';
11
13
  disabled?: boolean;
14
+ formGroupProps?: FormGroupProps;
12
15
  labelPlacement?: LabelPlacement;
16
+ labelProps?: TypographyTypeMap['props'];
13
17
  onChange?: (e) => void;
14
18
  options: Array<string>;
15
19
  values: Array<string>;
@@ -34,27 +38,32 @@ const CheckboxGroup = ({
34
38
  onChange,
35
39
  labelPlacement = 'end',
36
40
  disabled = false,
37
- dataTestId
41
+ dataTestId,
42
+ className,
43
+ labelProps,
44
+ formGroupProps
38
45
  }: Props): JSX.Element => {
39
- const { classes } = useStyles();
46
+ const { classes, cx } = useStyles();
40
47
 
41
48
  const row = !equals(direction, 'vertical');
42
49
 
43
50
  return (
44
51
  <FormGroup
45
- className={classes.container}
52
+ classes={{ root: classes.container }}
46
53
  data-testid={dataTestId || ''}
47
54
  row={row}
55
+ {...formGroupProps}
48
56
  >
49
57
  {options.map((value) => {
50
58
  return (
51
59
  <Checkbox
52
60
  checked={includes(value, values)}
53
- className={classes.checkbox}
61
+ className={cx(classes.checkbox, className)}
54
62
  disabled={disabled}
55
63
  key={value}
56
64
  label={value}
57
65
  labelPlacement={labelPlacement}
66
+ labelProps={labelProps}
58
67
  onChange={onChange}
59
68
  />
60
69
  );
@@ -92,7 +92,13 @@ export const useDashboardItemStyles = makeStyles<{ hasHeader: boolean }>()(
92
92
  '&[data-canMove="true"]': {
93
93
  cursor: 'move'
94
94
  },
95
- padding: theme.spacing(0.5, 2)
95
+ padding: theme.spacing(0.5, 2),
96
+ position: 'relative'
97
+ },
98
+ widgetHeaderDraggable: {
99
+ height: '100%',
100
+ position: 'absolute',
101
+ width: '100%'
96
102
  },
97
103
  widgetPadding: {
98
104
  overflowX: 'auto',
@@ -72,12 +72,12 @@ const Item = forwardRef(
72
72
  data-padding={!disablePadding}
73
73
  >
74
74
  {header && (
75
- <div
76
- {...listeners}
77
- className={classes.widgetHeader}
78
- data-canMove={canMove}
79
- data-testid={`${id}_move_panel`}
80
- >
75
+ <div className={classes.widgetHeader} data-canMove={canMove}>
76
+ <div
77
+ {...listeners}
78
+ className={classes.widgetHeaderDraggable}
79
+ data-testid={`${id}_move_panel`}
80
+ />
81
81
  {header}
82
82
  </div>
83
83
  )}
@@ -10,16 +10,15 @@ import IconClose from '@mui/icons-material/HighlightOff';
10
10
  const useStyles = makeStyles()((theme) => ({
11
11
  buttonClose: {
12
12
  position: 'absolute',
13
- right: theme.spacing(0.5),
14
- top: '40%'
13
+ right: theme.spacing(-0.5),
14
+ top: theme.spacing(-1)
15
15
  },
16
16
  tooltip: {
17
17
  backgroundColor: theme.palette.common.white,
18
18
  boxShadow: theme.shadows[3],
19
19
  color: theme.palette.text.primary,
20
20
  fontSize: theme.typography.pxToRem(12),
21
- maxWidth: 500,
22
- padding: theme.spacing(1, 2, 1, 1)
21
+ maxWidth: 500
23
22
  }
24
23
  }));
25
24
 
@@ -60,7 +59,7 @@ const PersistentTooltip = ({
60
59
  };
61
60
 
62
61
  const title = (
63
- <>
62
+ <div style={{ position: 'relative' }}>
64
63
  <IconButton
65
64
  className={classes.buttonClose}
66
65
  size="small"
@@ -69,7 +68,7 @@ const PersistentTooltip = ({
69
68
  <IconClose fontSize="small" />
70
69
  </IconButton>
71
70
  {children}
72
- </>
71
+ </div>
73
72
  );
74
73
 
75
74
  return (
@@ -82,34 +82,6 @@ describe('Multi connected autocomplete', () => {
82
82
  cy.makeSnapshot('hides the list when the user clicks on the input');
83
83
  });
84
84
 
85
- it('displays exactly one option on the list when the user types that option', () => {
86
- cy.get('[data-testid="Multi Connected Autocomplete"]').as('input');
87
-
88
- cy.get('@input').click();
89
-
90
- cy.waitForRequest('@getListOptions');
91
-
92
- cy.findByRole('presentation').as('listOptions');
93
-
94
- cy.get('@listOptions').should('be.visible');
95
-
96
- cy.get('@input').type(optionOne);
97
-
98
- cy.waitForRequest('@getSearchedOption');
99
-
100
- cy.fixture('inputField/searchedOption').then((optionData) => {
101
- cy.get('@listOptions')
102
- .find('li')
103
- .should('have.length', optionData.result.length);
104
- });
105
-
106
- cy.get('@listOptions').within(() => {
107
- cy.contains(optionOne).should('be.visible');
108
- });
109
-
110
- cy.makeSnapshot();
111
- });
112
-
113
85
  it('displays all options on the list when the user searches for and selects an option', () => {
114
86
  cy.get('[data-testid="Multi Connected Autocomplete"]').as('input');
115
87
 
@@ -125,13 +97,11 @@ describe('Multi connected autocomplete', () => {
125
97
 
126
98
  cy.waitForRequest('@getSearchedOption');
127
99
 
128
- cy.fixture('inputField/searchedOption').then((optionData) => {
129
- cy.get('@listOptions')
130
- .find('li')
131
- .should('have.length', optionData.result.length);
100
+ cy.fixture('inputField/searchedOption').then(() => {
101
+ cy.get('@listOptions').find('li').should('have.length', 5);
132
102
  });
133
103
 
134
- cy.get('[type="checkbox"]').check();
104
+ cy.get('[type="checkbox"]').eq(0).check();
135
105
  cy.get('@input')
136
106
  .parent()
137
107
  .within(() => {
@@ -153,7 +123,5 @@ describe('Multi connected autocomplete', () => {
153
123
  });
154
124
  });
155
125
  });
156
-
157
- cy.makeSnapshot();
158
126
  });
159
127
  });
@@ -95,9 +95,7 @@ describe(SingleConnectedAutocompleteField, () => {
95
95
 
96
96
  await waitFor(() => {
97
97
  expect(getFetchCall(2)).toEqual(
98
- `${baseEndpoint}?page=1&search=${encodeURIComponent(
99
- '{"$and":[{"host.name":{"$lk":"%My Option 2%"}}]}'
100
- )}`
98
+ `${baseEndpoint}?page=1&search=%7B%22%24and%22%3A%5B%7B%22%24or%22%3A%5B%7B%22host.name%22%3A%7B%22%24lk%22%3A%22%25My%20Option%202%25%22%7D%7D%5D%7D%5D%7D`
101
99
  );
102
100
  });
103
101
  });
@@ -118,9 +116,7 @@ describe(SingleConnectedAutocompleteField, () => {
118
116
 
119
117
  await waitFor(() => {
120
118
  expect(getFetchCall(0)).toEqual(
121
- `${baseEndpoint}?page=1&search=${encodeURIComponent(
122
- '{"$and":[{"parent_name":{"$eq":"Centreon-Server"}}]}'
123
- )}`
119
+ `${baseEndpoint}?page=1&search=%7B%22%24and%22%3A%5B%7B%22%24or%22%3A%5B%7B%22parent_name%22%3A%7B%22%24eq%22%3A%22Centreon-Server%22%7D%7D%5D%7D%5D%7D`
124
120
  );
125
121
  });
126
122
  });
@@ -53,24 +53,27 @@ const MultiAutocompleteField = ({
53
53
  const { classes } = useStyles();
54
54
 
55
55
  const renderTags = (renderedValue, getTagProps): Array<JSX.Element> =>
56
- renderedValue.map((option, index) => (
57
- <Tooltip
58
- key={option.id}
59
- placement="top"
60
- title={getOptionTooltipLabel?.(option)}
61
- >
62
- <Chip
63
- classes={{
64
- deleteIcon: classes.deleteIcon,
65
- root: classes.tag
66
- }}
67
- label={getTagLabel(option)}
68
- size="medium"
69
- {...getTagProps({ index })}
70
- {...chipProps}
71
- />
72
- </Tooltip>
73
- ));
56
+ renderedValue.map((option, index) => {
57
+ return (
58
+ <Tooltip
59
+ key={option.id}
60
+ placement="top"
61
+ title={getOptionTooltipLabel?.(option)}
62
+ >
63
+ <Chip
64
+ classes={{
65
+ deleteIcon: classes.deleteIcon,
66
+ root: classes.tag
67
+ }}
68
+ label={getTagLabel(option)}
69
+ size="medium"
70
+ {...getTagProps({ index })}
71
+ {...chipProps}
72
+ onDelete={(event) => chipProps?.onDelete?.(event, option)}
73
+ />
74
+ </Tooltip>
75
+ );
76
+ });
74
77
 
75
78
  const getLimitTagsText = (more): JSX.Element => <Option>{`+${more}`}</Option>;
76
79
 
@@ -1,4 +1,4 @@
1
- import { useState, useEffect } from 'react';
1
+ import { Dispatch, SetStateAction, useEffect, useState } from 'react';
2
2
 
3
3
  import { makeStyles } from 'tss-react/mui';
4
4
 
@@ -9,6 +9,7 @@ import {
9
9
  PopperPlacementType,
10
10
  useTheme
11
11
  } from '@mui/material';
12
+ import { PopperProps } from '@mui/material/Popper';
12
13
 
13
14
  import { IconButton } from '..';
14
15
 
@@ -19,15 +20,22 @@ const useStyles = makeStyles()(() => ({
19
20
  }
20
21
  }));
21
22
 
23
+ interface PopoverData {
24
+ anchorEl: HTMLElement | undefined;
25
+ setAnchorEl: Dispatch<SetStateAction<HTMLElement | undefined>>;
26
+ }
27
+
22
28
  interface Props {
23
29
  canOpen?: boolean;
24
30
  children: (props?) => JSX.Element;
25
31
  className?: string;
26
32
  dataTestId?: string;
33
+ getPopoverData?: (data: PopoverData) => void;
27
34
  icon: JSX.Element;
28
35
  onClose?: () => void;
29
36
  onOpen?: () => void;
30
37
  popperPlacement?: PopperPlacementType;
38
+ popperProps?: Partial<PopperProps>;
31
39
  title?: string;
32
40
  }
33
41
 
@@ -40,20 +48,21 @@ const PopoverMenu = ({
40
48
  onClose,
41
49
  canOpen = true,
42
50
  className,
43
- dataTestId
51
+ dataTestId,
52
+ getPopoverData,
53
+ popperProps
44
54
  }: Props): JSX.Element => {
45
55
  const theme = useTheme();
46
56
  const { classes, cx } = useStyles();
47
57
  const [anchorEl, setAnchorEl] = useState<HTMLElement | undefined>();
48
-
49
58
  const isOpen = Boolean(anchorEl);
50
59
 
51
60
  const close = (reason?): void => {
52
61
  const isClosedByInputClick = reason?.type === 'mousedown';
53
-
54
62
  if (isClosedByInputClick) {
55
63
  return;
56
64
  }
65
+
57
66
  onClose?.();
58
67
  setAnchorEl(undefined);
59
68
  };
@@ -75,6 +84,10 @@ const PopoverMenu = ({
75
84
  }
76
85
  }, [canOpen]);
77
86
 
87
+ useEffect(() => {
88
+ getPopoverData?.({ anchorEl, setAnchorEl });
89
+ }, [anchorEl]);
90
+
78
91
  return (
79
92
  <>
80
93
  <IconButton
@@ -97,6 +110,7 @@ const PopoverMenu = ({
97
110
  style={{ zIndex: theme.zIndex.tooltip }}
98
111
  onResize={(): undefined => undefined}
99
112
  onResizeCapture={(): undefined => undefined}
113
+ {...popperProps}
100
114
  >
101
115
  <Paper>{children({ close })}</Paper>
102
116
  </Popper>
@@ -38,6 +38,7 @@ export interface RichTextEditorProps {
38
38
  openLinkInNewTab?: boolean;
39
39
  placeholder?: string;
40
40
  resetEditorToInitialStateCondition?: () => boolean;
41
+ toolbarClassName?: string;
41
42
  toolbarPositions?: 'start' | 'end';
42
43
  }
43
44
 
@@ -136,7 +137,8 @@ const RichTextEditor = ({
136
137
  disabled = false,
137
138
  openLinkInNewTab = true,
138
139
  initialize,
139
- displayBlockButtons = true
140
+ displayBlockButtons = true,
141
+ toolbarClassName
140
142
  }: RichTextEditorProps): JSX.Element => {
141
143
  const { classes } = useStyles({ toolbarPositions });
142
144
 
@@ -175,6 +177,7 @@ const RichTextEditor = ({
175
177
  <div className={classes.container}>
176
178
  <div className={classes.toolbar}>
177
179
  <ToolbarPlugin
180
+ className={toolbarClassName}
178
181
  disabled={disabled}
179
182
  displayBlockButtons={displayBlockButtons}
180
183
  displayMacrosButton={displayMacrosButton}
@@ -9,6 +9,7 @@ import BlockButtons from './BlockButtons';
9
9
  import AlignPicker from './AlignPicker';
10
10
 
11
11
  interface Props {
12
+ className?: string;
12
13
  disabled: boolean;
13
14
  displayBlockButtons: boolean;
14
15
  displayMacrosButton?: boolean;
@@ -36,12 +37,13 @@ const ToolbarPlugin = ({
36
37
  editable,
37
38
  displayMacrosButton,
38
39
  disabled,
39
- displayBlockButtons
40
+ displayBlockButtons,
41
+ className
40
42
  }: Props): JSX.Element | null => {
41
- const { classes } = useStyles();
43
+ const { cx, classes } = useStyles();
42
44
 
43
45
  return editable ? (
44
- <div className={classes.container}>
46
+ <div className={cx(classes.container, className)}>
45
47
  <UndoRedoButtons disabled={disabled} />
46
48
  {displayBlockButtons && (
47
49
  <>
@@ -51,13 +53,13 @@ const ToolbarPlugin = ({
51
53
  )}
52
54
  <Divider flexItem orientation="vertical" />
53
55
  <FormatButtons disabled={disabled} />
56
+ <AlignPicker disabled={disabled} />
54
57
  {displayMacrosButton && (
55
58
  <>
56
59
  <Divider flexItem orientation="vertical" />
57
60
  <MacrosButton disabled={disabled} />
58
61
  </>
59
62
  )}
60
- <AlignPicker disabled={disabled} />
61
63
  </div>
62
64
  ) : null;
63
65
  };
@@ -29,6 +29,7 @@ const actionsBarLabelsDefaultValues = {
29
29
  };
30
30
 
31
31
  const Wizard = ({
32
+ classNameDialogContent,
32
33
  steps,
33
34
  onSubmit = undefined,
34
35
  initialValues = {},
@@ -41,7 +42,7 @@ const Wizard = ({
41
42
  displayConfirmDialog,
42
43
  ...rest
43
44
  }: WizardProps): JSX.Element => {
44
- const { classes } = useStyles();
45
+ const { classes, cx } = useStyles();
45
46
  const [currentStep, setCurrentStep] = useState(0);
46
47
  const [sendingRequest, setSendingRequest] = useState(false);
47
48
  const [openConfirm, setOpenConfirm] = useState(false);
@@ -131,7 +132,9 @@ const Wizard = ({
131
132
  validationSchema={validationSchema}
132
133
  onSubmit={submit}
133
134
  >
134
- <DialogContent className={classes.dialogContent}>
135
+ <DialogContent
136
+ className={cx(classes.dialogContent, classNameDialogContent)}
137
+ >
135
138
  <WizardContent
136
139
  actionsBarLabels={actionsBarLabels}
137
140
  currentStep={currentStep}
@@ -45,6 +45,7 @@ type ValueOf<T> = T[keyof T];
45
45
  export interface WizardProps {
46
46
  [key: string]: ValueOf<DialogProps>;
47
47
  actionsBarLabels?: ActionsBarLabels;
48
+ classNameDialogContent?: string;
48
49
  confirmDialogLabels?: ConfirmDialogLabels;
49
50
  displayConfirmDialog?: boolean;
50
51
  fullHeight?: boolean;
@@ -5,9 +5,10 @@ import {
5
5
  prop,
6
6
  head,
7
7
  toPairs,
8
- pipe,
9
- map,
10
- flatten
8
+ flatten,
9
+ pluck,
10
+ uniq,
11
+ equals
11
12
  } from 'ramda';
12
13
 
13
14
  import {
@@ -21,7 +22,7 @@ import {
21
22
  GetConditionsSearchQueryParameterValueState
22
23
  } from './models';
23
24
 
24
- const getFoundFields = ({
25
+ export const getFoundFields = ({
25
26
  value,
26
27
  fields
27
28
  }: RegexSearchParameter): Array<SearchMatch> => {
@@ -83,32 +84,42 @@ const getConditionsSearchQueryParameterValue = (
83
84
  return undefined;
84
85
  }
85
86
 
86
- const toIndividualOperatorValues = ({
87
- field,
88
- values,
89
- value
90
- }: ConditionsSearchParameter): Array<Record<string, unknown>> => {
91
- if (!isNil(value)) {
92
- return [
93
- {
94
- [field]: value
95
- }
96
- ];
97
- }
98
-
99
- return toPairs(values || {}).map(([operator, operatorValue]) => ({
100
- [field]: {
101
- [operator]: operatorValue
102
- }
103
- }));
87
+ const fields = uniq(pluck('field', conditions));
88
+
89
+ const toIndividualOperatorValues = (
90
+ listField: string
91
+ ): { $or: Array<Record<string, unknown>> } => {
92
+ const filteredItems = conditions.filter(({ field }) =>
93
+ equals(listField, field)
94
+ );
95
+
96
+ return {
97
+ $or: flatten(
98
+ filteredItems.map(({ value, values }) => {
99
+ if (!isNil(value)) {
100
+ return [
101
+ {
102
+ [listField]: value
103
+ }
104
+ ];
105
+ }
106
+
107
+ return toPairs(values || {}).map(([operator, operatorValue]) => ({
108
+ [listField]: {
109
+ [operator]: operatorValue
110
+ }
111
+ }));
112
+ })
113
+ )
114
+ };
104
115
  };
105
116
 
106
117
  return {
107
- $and: pipe(map(toIndividualOperatorValues), flatten)(conditions)
118
+ $and: fields.map(toIndividualOperatorValues)
108
119
  };
109
120
  };
110
121
 
111
- const getSearchQueryParameterValue = (
122
+ export const getSearchQueryParameterValue = (
112
123
  search: SearchParameter | undefined
113
124
  ): SearchQueryParameterValue => {
114
125
  if (search === undefined) {
@@ -134,5 +145,3 @@ const getSearchQueryParameterValue = (
134
145
 
135
146
  return { $and: result };
136
147
  };
137
-
138
- export default getSearchQueryParameterValue;
@@ -115,7 +115,7 @@ describe(buildListingEndpoint, () => {
115
115
  });
116
116
 
117
117
  expect(decodeURIComponent(endpointWithValues)).toContain(
118
- '&search={"$and":[{"date":{"$gt":"2020-12-01T07:00:00"}},{"date":{"$lt":"2020-12-01T11:00:00"}}]}'
118
+ '&search={"$and":[{"$or":[{"date":{"$gt":"2020-12-01T07:00:00"}},{"date":{"$lt":"2020-12-01T11:00:00"}}]}]}'
119
119
  );
120
120
 
121
121
  const endpointWithValue = buildListingEndpoint({
@@ -134,7 +134,7 @@ describe(buildListingEndpoint, () => {
134
134
  });
135
135
 
136
136
  expect(decodeURIComponent(endpointWithValue)).toContain(
137
- '&search={"$and":[{"is_activated":true}]}'
137
+ '&search={"$and":[{"$or":[{"is_activated":true}]}]}'
138
138
  );
139
139
  });
140
140
  });
@@ -1,7 +1,7 @@
1
1
  import toRawQueryParameters from '../../queryParameters';
2
2
  import { QueryParameter } from '../../queryParameters/models';
3
3
 
4
- import getSearchQueryParameterValue from './getSearchQueryParameterValue';
4
+ import { getSearchQueryParameterValue } from './getSearchQueryParameterValue';
5
5
  import { Parameters, BuildListingEndpointParameters } from './models';
6
6
 
7
7
  const getQueryParameters = ({
@@ -18,7 +18,6 @@ export interface Parameters {
18
18
  search?: SearchParameter;
19
19
  sort?: SortQueryParameterValue;
20
20
  }
21
-
22
21
  export interface SearchParameter {
23
22
  conditions?: Array<ConditionsSearchParameter>;
24
23
  lists?: Array<ListsSearchParameter>;
package/src/index.ts CHANGED
@@ -75,7 +75,10 @@ export { default as useCancelTokenSource } from './api/useCancelTokenSource';
75
75
  export { getData, patchData, postData, putData, deleteData } from './api';
76
76
  export { default as useRequest } from './api/useRequest';
77
77
  export { default as buildListingEndpoint } from './api/buildListingEndpoint';
78
- export { default as getSearchQueryParameterValue } from './api/buildListingEndpoint/getSearchQueryParameterValue';
78
+ export {
79
+ getSearchQueryParameterValue,
80
+ getFoundFields
81
+ } from './api/buildListingEndpoint/getSearchQueryParameterValue';
79
82
  export type {
80
83
  Parameters as ListingParameters,
81
84
  BuildListingEndpointParameters,
@@ -1,4 +1,4 @@
1
- import { useRef, useCallback } from 'react';
1
+ import { useRef, useCallback, useEffect } from 'react';
2
2
 
3
3
  interface Props {
4
4
  functionToDebounce: (...args) => void;
@@ -12,6 +12,11 @@ export const useDebounce = ({
12
12
  memoProps = []
13
13
  }: Props): ((...args) => void) => {
14
14
  const timeoutRef = useRef<number | null>(null);
15
+ const ref = useRef();
16
+
17
+ useEffect(() => {
18
+ ref.current = functionToDebounce;
19
+ }, [functionToDebounce]);
15
20
 
16
21
  return useCallback((...args): void => {
17
22
  if (timeoutRef.current) {
@@ -19,7 +24,7 @@ export const useDebounce = ({
19
24
  }
20
25
 
21
26
  timeoutRef.current = setTimeout(() => {
22
- functionToDebounce(...args);
27
+ ref.current?.(...args);
23
28
  }, wait);
24
29
  }, memoProps);
25
30
  };