# hooks
A collection of useful hooks

## useRefdata
A hook for fetching refdata values
### Basic usage
```javascript
import { useRefdata } from '@k-int/stripes-kint-components'
...
const data = useRefdata({
  desc: 'PublicationRequest.PublicationType',
  endpoint: 'oa/refdata'
});
...
```

### Props
| Name              | Type   | Description                                                                                                                                                                                                                                                                                                  | default                                                    | required |
|-------------------|--------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------|----------|
| endpoint          | string | The endpoint to fetch refdataValues from                                                                                                                                                                                                                                                                     |                                                            | ✓        |
| desc              | string | The refdataCategory (usually of the form `DomainClass.Field`)                                                                                                                                                                                                                                                |                                                            | ✕        |
| queryParams       | object | A set of queryParameters to hand to react-query's `useQuery`                                                                                                                                                                                                                                                 |                                                            | ✕        |
| returnQueryObject | bool   | A switch to return the entirety of the queryObject from useQuery. If `false`, the data will be destructured, if `true` the return will be the full object returned by react-query's `useQuery`                                                                                                               | false                                                      | ✕        |
| options           | object | An object of the shape SASQ_MAP (See generateKiwtQuery) to pass to the generateKiwtQuery inside. Any passed desc "d" will be passed as a filter `DescKey.${d}`, with DescKey acting as FilterName, assuming `filterKeys: { DescKey: "desc" }` in options, so `desc==${d}` is passed directly to the backend. | `{filterKeys: {DescKey: "desc" }, stats: false, max: 100}` | ✕        |


## useActiveElement
A hook which returns the currently focused element in the document, `active`, as well as a function `hasParent`.
The hooks works by creating a listener on the document for the `focusin` event and then setting state using `document.activeElement`.
### Basic usage
```javascript
import { useActiveElement } from '@k-int/stripes-kint-components'
...
const { active, hasParent } = useActiveElement();
...
```

### hasParent
The function `hasParent` takes a single string as a prop, and returns `true` if and only if the currently active element is a child of some element with `id` attribute matching the regex `[id^=${id}]`.
Usage is as follows:
```javascript
  const { hasParent } = useActiveElement();
  const openBool = hasParent('typedown-parent');
```

## useHelperApp
A hook which takes an object containing various helper components to render, and handles the url logic to decide which one to render.
When the url contains a query of the form `helper={name}`, this hook will check the helpers object it was handed for a key matching `{name}`, and if there is one it will return the component value for that key.

The hook also returns an object `helperToggleFunctions`, which will have the same keys as were handed to the hook, and values corresponding to "toggle" functions for that key. These functions are a simple way to change the helper query in the url.

Finally the hook also returns an ease-of-use function `isOpen`, which takes a string input and returns a boolean if the current helper in the URL matches that string or not.
### Basic usage
```javascript
import { useHelperApp } from '@k-int/stripes-kint-components'
...
const ChatPane = () => { ... }
const Tags = () => { ... }
...
const { HelperComponent, helperToggleFunctions } = useHelperApp({
  chat: ChatPane,
  tags: Tags
});
...

return (
  <>
    <button onClick={helperToggleFunctions.chat}> Chat </button>
    <button onClick={helperToggleFunctions.tags}> Tags </button>
    < ... />
    <HelperComponent />
  </>
);
```

### Props
| Name    | Type   | Description                                                                                                                                                                                                                | default | required |
|---------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------|----------|
| helpers | object | An object of the form `{helperKey1: Component1, helperKey2: Component1}` where `Component1`/`Component1` are components to be rendered when the url contains query `helper=helperKey1` or `helper=helperKey2` respectively |         | ✓        |

## useKiwtSASQuery
A hook which sets up a basic queryGetter and querySetter for use with SASQ, as well as setting up the query object itself. Will often be used with the `generateKiwtQuery` function from `utils`.

### Basic usage
```javascript
import { generateKiwtQuery, useKiwtSASQuery } from '@k-int/stripes-kint-components';
import { useOkapiKy } from '@folio/stripes/core';
import { useQuery } from 'react-query';

...
  const { query, queryGetter, querySetter } = useKiwtSASQuery();

  const SASQ_MAP = {
    searchKey: 'requestStatus.value',
    filterKeys: {
      requestStatus: 'requestStatus.value'
    }
  };

  const ky = useOkapiKy();

  const { data } = useQuery(
    ['ui-oa', 'oaRoute', 'publicationRequests', query],
    () => ky(`oa/publicationRequest${generateKiwtQuery(SASQ_MAP, query)}`).json()
  );
...
  return (
    <SearchAndSortQuery
      initialSearchState={{ query: '' }}
      queryGetter={queryGetter}
      querySetter={querySetter}
    >
    ...
    </SearchAndSortQuery>

```

## useQIndex
A hook with a similar API to setState, but instead stores a value in the `qindex` parameter in the URL.
Returns an array `[qindex, setQindex]`. There is no way to set an initialValue with the hook, as the state is derived from the URL rather than the other way around. This means that multiple `useQIndex` hooks can exist at once.

### BasicUsage
```javascript
import {
  Button,
} from '@folio/stripes/components';
import useQindex from '../../../../stripes-kint-components/src/lib/hooks/useQIndex';

const Test() {
  const [qindex, setQindex] = useQindex();

  return (
    <>
      <Button
        onClick={() => setQindex(qindex + "1")}
      >
        change the qindex
      </Button>
      <div>
        {`The current qindex is: ${qindex}`
      </div>
    </>
  );
}

export default Test;
```

## useKiwtFieldArray
A hook to replace `withKiwtFieldArray` [from stripes-erm-components](https://github.com/folio-org/stripes-erm-components/tree/master/lib/withKiwtFieldArray). Provides functions for adding and deleting items in a way which the backend endpoints will understand, as well as an "items" array to track the current set of valid items in the form.


### BasicUsage
```javascript
...
import useKiwtFieldArray from '../../../util/useKiwtFieldArray';
...

const TestFieldArray = () => {
  const {
    items,
    onAddField,
    onDeleteField
  } = useKiwtFieldArray(name, true);

  return (
    <>
      {items.map((item, index) => {
        return (
          <Row>
            <Col xs={3}>
              <Field
                name={`${name}[${index}].name`}
                component={TextField}
                required
                validate={requiredValidator}
              />
            </Col>
            <Col xs={1}>
              <IconButton
                icon="trash"
                id="remove-volume-button"
                onClick={() => onDeleteField(index, volume)}
              />
            </Col>
          </Row>
        );
      })}
      <Button
        onClick={() => onAddField({}})}
      >
        ADD NEW
      </Button>
    </>
  );
};

const Test = ({}) => {
  return (
    <Form
      ...
      render={({ handleSubmit, submitting, form }) => (
        <form onSubmit={handleSubmit}>
          <FieldArray
            name="test"
            component={TestFieldArray}
          />
        </form>
      )}
    />
  );
};
export default Test
```

### Props
| Name                     | Type   | Description                                                                                             | default | required |
|--------------------------|--------|---------------------------------------------------------------------------------------------------------|---------|----------|
| name                     | String | The name of the fieldArray, used to hook into the final form state for that field.                      |         | ✓        |
| submitWholeDeletedObject | bool   | a boolean flag to ensure that a deleted object is sent whole to the backend, rather than just as an id. | false   | ✕        |

## useMutateGeneric

A generic hook for mutations (Create/Delete/Edit) with customizable logic.

### Basic Usage

```javascript
import useMutateGeneric from '@k-int/stripes-kint-components';

const { delete: deleteObject, post: createObject, put: updateObject } = useMutateGeneric({
  endpoint: 'your/endpoint',
  queryKey: ['your', 'query', 'key'],
});

// Example usage:
deleteObject(123) // Deletes the object with id 123
createObject({ name: 'New Object' }) // Creates a new object with the given data
updateObject({ id: 456, name: 'Updated Object' }) // Updates the object with id 456
```

### Props

| Name              | Type   | Description                                                                                                                                                                                                                                                                                                                                        | Default                                                                                                                         | Required |
|-------------------|--------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------------------------------|----------|
| afterQueryCalls   | object | An object of the form `{ delete: func1, post: func2, put: func3 }` where `func1(responseData)`, `func2(responseData)`, and `func3(responseData)` are functions to be called *after* the corresponding mutation is successful. `responseData` is the data returned by the API call.                                                                 | `{}`                                                                                                                            | ✕        |
| catchQueryCalls   | object | An object of the form `{ delete: func1, post: func2, put: func3 }` where `func1(error)`, `func2(error)`, and `func3(error)` are functions to be called *if* the corresponding mutation fails. `error` is the HTTPError object.                                                                                                                     | `{}`                                                                                                                            | ✕        |
| endpoint          | string | The base endpoint for the API calls.                                                                                                                                                                                                                                                                                                               |                                                                                                                                 | ✓        |
| endpointMutators  | object | An object of the form `{ delete: func1, post: func2, put: func3 }` where `func1(id)`, `func2()`, and `func3(data)` are functions that modify the endpoint for each operation.  Defaults to appending the id for `delete` and `put`, and using the base endpoint for `post`.                                                                        | `{ delete: (id) => "${endpoint}/${id}", post: () => endpoint, put: (data) => "${endpoint}/${data.id}" }`                        | ✕        |
| payloadMutators   | object | An object of the form `{ post: func1, put: func2 }` where `func1(data)` and `func2(data)` are functions that modify the payload for the `post` and `put` operations. Defaults to wrapping the data in a `json` object.                                                                                                                             | `{ post: (data) => ({ json: data }), put: (data) => ({ json: data }) }`                                                         | ✕        |
| promiseReturns    | object | An object of the form `{ delete: func1, post: func2, put: func3 }` where `func1(id, ky)`, `func2(data, ky)`, and `func3(data, ky)` are functions that define the promise return for each operation. Allows full control over the `ky` call.  `id` is the id for delete, `data` is the data being sent for post/put, and `ky` is the `ky` instance. | `{ delete: (id, ky) => ky.delete(...).json(), post: (data, ky) => ky.post(...).json(), put: (data, ky) => ky.put(...).json() }` | ✕        |
| queryKey          | array  | The query key to be used with `react-query`.  **Must be an array.**                                                                                                                                                                                                                                                                                | `[]`                                                                                                                            | ✓        |
| queryKeyMutators  | object | An object of the form `{ delete: func1, post: func2, put: func3 }` where `func1()`, `func2()`, and `func3()` are functions that return the query key for each mutation.                                                                                                                                                                            | `{ delete: () => [...queryKey, 'delete'], post: () => [...queryKey, 'create'], put: () => [...queryKey, 'edit'] }`              | ✕        |
| queryParams       | object | An object of the form `{ delete: obj1, post: obj2, put: obj3 }` where `obj1`, `obj2`, and `obj3` are the query parameters for each operation.                                                                                                                                                                                                      | `{}`                                                                                                                            | ✕        |
| returnQueryObject | object | An object of the form `{ delete: bool1, post: bool2, put: bool3 }` containing switches to return the entire query object from `useMutation` for each operation. If `false` (the default), the `mutateAsync` function will be returned; if `true`, the full object (including `mutate`, `isLoading`, `error`, etc.) will be returned.               | `{ delete: false, post: false, put: false }`                                                                                    | ✕        |
## useCustProps
A hook for fetching custom property definitions using batched parallel requests.

This hook replaces `useCustomProperties` as the preferred way of retrieving custom property definitions. It uses `useParallelBatchFetch` internally to ensure that all available custom properties are fetched even when the backend paginates responses.

### Why this hook exists
The previous `useCustomProperties` hook relied on a single request with `max: 100`, which meant that only the first 100 custom properties could be retrieved. In environments with more definitions this led to incomplete data.

`useCustProps` resolves this by:
- using batched requests with controlled concurrency
- retrieving all available custom property definitions
- maintaining compatibility with existing query key patterns used across `stripes-kint-components`

### Basic usage
```javascript
  const { custprops, isLoading } = useCustProps({
    ctx,
    endpoint: customPropertiesEndpoint,
  });
  ```
  ### Props
  | Name               | Type              | Description                                                                 | Default           | Required |
|--------------------|------------------|-----------------------------------------------------------------------------|-------------------|----------|
| endpoint           | string            | Backend endpoint used to retrieve custom property definitions              |                   | ✓        |
| ctx                | string \| string[]| Context or contexts used to filter custom properties                       |                   | ✕        |
| nsValues           | object            | Additional namespace query parameters passed to generateKiwtQueryParams    | { sort: 'id' }    | ✕        |
| options            | object            | Additional query configuration merged into the custom property query       | {}                | ✕        |
| queryParams        | object            | Options forwarded to the underlying react-query calls                      | {}                | ✕        |
| batchLimit         | number            | Maximum number of records to fetch                                          | Infinity          | ✕        |
| batchSize          | number            | Number of records fetched per batch                                         | 100               | ✕        |
| concurrentRequests | number            | Number of concurrent requests made when fetching batches                    | 5                 | ✕        |

## useCustomProperties
Legacy hook for fetching custom property definitions.

This hook performs a single request using a `max` parameter (typically `100`) and therefore only retrieves the first page of results. In environments where more than 100 custom properties exist, this can lead to incomplete data.

### Recommendation
Where possible it is recommended to migrate to:

- `useCustProps` for retrieving custom property definitions
- or one of the shared components such as:
  - `CustomPropertiesLookup`
  - `CustomPropertiesView`
  - `CustomPropertiesSettings`

These components already use `useCustProps` internally and ensure consistent behaviour.

`useCustomProperties` remains available for backwards compatibility but may be deprecated in the future.

### Basic usage
```javascript
import { useCustomProperties } from '@k-int/stripes-kint-components';

const { data, isLoading } = useCustomProperties({
  endpoint: '/erm/custom-properties',
  returnQueryObject: true
});
```
### Props
| Name              | Type              | Description                                                               | Default        | Required |
|-------------------|------------------|---------------------------------------------------------------------------|---------------|----------|
| endpoint          | string            | Backend endpoint used to retrieve custom property definitions            |               | ✓        |
| ctx               | string \| string[]| Context or contexts used to filter custom properties                     |               | ✕        |
| nsValues          | object            | Additional namespace query parameters passed to generateKiwtQuery        | { sort: 'id'} | ✕        |
| options           | object            | Additional query configuration merged into the custom property query     | {}            | ✕        |
| queryParams       | object            | Options forwarded to the underlying react-query call                     | {}            | ✕        |
| returnQueryObject | boolean           | If true, the full react-query result object is returned instead of data | false         | ✕        |
## useParallelBatchFetch
A generic hook for performing batched parallel API requests.

This hook is designed to fetch paginated resources in multiple requests while limiting the number of concurrent requests. It was originally introduced in `stripes-erm-components` and has been incorporated into `stripes-kint-components` to maintain consistency across libraries.

The hook performs the following steps:

1. Fetches the first page of results to determine the total record count.
2. Generates additional requests using offsets.
3. Executes batches of requests in parallel with a configurable concurrency limit.
4. Returns a flattened array of results.

### Basic usage
```javascript
import useParallelBatchFetch from '@k-int/stripes-kint-components/hooks/useParallelBatchFetch';

const { items, isLoading, total } = useParallelBatchFetch({
  endpoint: '/erm/custom-properties'
});
```
### Props
| Name                | Type     | Description                                                         | Default                     | Required |
|---------------------|----------|---------------------------------------------------------------------|-----------------------------|----------|
| endpoint            | string   | Endpoint used for fetching resources                                |                             | ✓        |
| batchParams         | object   | Query configuration passed to generateKiwtQueryParams               | {}                          | ✕        |
| nsValues            | object   | Additional namespace query parameters                               | {}                          | ✕        |
| BATCH_SIZE          | number   | Number of records fetched per request                               | 100                         | ✕        |
| CONCURRENT_REQUESTS | number   | Maximum number of parallel requests                                 | 5                           | ✕        |
| BATCH_LIMIT         | number   | Maximum number of records to fetch                                  | Infinity                    | ✕        |
| generateQueryKey    | function | Optional function used to generate custom react-query keys          |                             | ✕        |
| queryOptions        | object   | Options passed to the underlying react-query calls                  | {}                          | ✕        |
| queryNamespace      | string   | Namespace used for the default query key                            | 'stripes-kint-components'   | ✕        |
