All Downloads are FREE. Search and download functionalities are using the official Maven repository.

package.react-utils.d.ts Maven / Gradle / Ivy

Go to download

A package encapsulating common code across neeto projects including initializers, utility functions, common components and hooks and so on.

There is a newer version: 4.12.3
Show newest version
import React, { ComponentType, ElementType, ReactNode } from "react";
import { RouteProps } from "react-router-dom";
import { Notice } from "@honeybadger-io/js/dist/server/types/core/types";
import { History } from "history";
import { StoreApi, UseBoundStore } from "zustand";
import { UseQueryOptions, UseQueryResult, UseMutationOptions, UseMutationResult, QueryKey, MutationFunction } from "@tanstack/react-query";
import { KeyPrefix, Namespace } from "i18next";
import { DefaultNamespace } from "react-i18next/TransWithoutContext";
import { qsOptionsType, QueryParamsType } from "./utils";
import { QueryFilters } from "react-query/types/core/utils";
import BrowserSupport from "@bigbinary/neeto-molecules/types/BrowserSupport";
type HoneybadgerErrorBoundaryPropsType = {
  ErrorComponent?: ReactNode | ComponentType | ElementType;
  filterErrors?: (error: Notice) => boolean;
  children?: ReactNode;
};
type BrowserSupportPropsType = React.ComponentProps;
/**
 *
 * The HoneybadgerErrorBoundary is an ErrorBoundary which reports frontend errors
 *
 * to HoneyBadger.
 *
 * This component will wrap its children with the error boundary provided by
 *
 * @honeybadger-io/react package. In this component, we will create a honeybadger
 *
 * configuration object using the API key, environment and project version which we
 *
 * obtained from the globalProps and pass the created object to error boundary
 *
 * provided by honeybadger. We are also filtering the false-positive errors using
 *
 * beforeNotify method.
 *
 * For global error handling, we need to wrap the Main component with this
 *
 * HoneybadgerErrorBoundary component as shown below.
 *
 * @example 
 *
 *  !/IgnorableError/.test(notice.message)}
 * >
 *   
* * @endexample * ErrorComponent is the component which will be rendered when an error is thrown * * during rendering. This is an optional prop and if this prop is not provided then * * honeybadger will use DefaultErrorComponent for fallback UI. * * filterErrors is a function which takes the honeybadger notice as argument and * * returns a boolean. It should return true if the error is to be reported and * * false if not. * */ export const HoneybadgerErrorBoundary: React.FC; /** * * The QueryClientProvider component wraps the application with a query client provider from @tanstack/react-query, facilitating data fetching and caching capabilities across the application using a predefined queryClient. * * @example * * import QueryClientProvider from "@bigbinary/neeto-commons-frontend/react-utils/QueryClientProvider"; * * const App = () => ( * * { Main application components } * * * ); * * export default App; * @endexample */ export const QueryClientProvider: React.FC<{ children?: ReactNode; }>; /** * * The AppContainer component serves as a wrapper around your main application components,it includes error handling with HoneybadgerErrorBoundary, browser support detection with BrowserSupport, client-side routing with BrowserRouter, query management with QueryClientProvider, and development tools with ReactQueryDevtools. * * @example * * import AppContainer from "@bigbinary/neeto-commons-frontend/react-utils/AppContainer"; * * const App = () => ( * !/IgnorableError/.test(notice.message), * }} * browserSupportProps={{ * checkOnMount: true, * unsupportedBrowserComponent: UnsupportedBrowserComponent, * }} * reactQueryDevtoolsProps={{ * initialIsOpen: true, * position: "bottom-right", * }} * enableStickyRibbons={true} * > * { Main application components } * * * ); * * export default App; * @endexample */ export const AppContainer: React.FC<{ children?: ReactNode; honeybadgerErrorBoundaryProps?: HoneybadgerErrorBoundaryPropsType; browserSupportProps?: BrowserSupportPropsType; reactQueryDevtoolsProps?: { [key: string]: any; }; toastContainerProps?: { [key: string]: any; }; enableStickyRibbons?: boolean; }>; /** * * PrivateRoute is a route that will restrict access to it based on a specified * * condition and permissions. * * If the given condition is true and the user has the required permissions, it * * acts identical to a normal route. If the condition is true and the user does not * * have the required permissions, it will show 403 error page or it will render a * * supplied error page. If the condition is false, it will redirect user to a * * different path if redirectRoute is specified or it will render a supplied error * * page. * * If condition is not specified, it will assume the value of * * globalProps.authenticated by default. * * Here are some example use cases: * */ export function PrivateRoute(props: { condition?: boolean; redirectRoute?: string; errorPage?: React.ReactNode; permissions?: string[]; } & RouteProps): JSX.Element; type OptionsType = { root?: Element | null; rootMargin?: String; threshold?: Number | Number[]; }; /** * * Component to set the page title. * * @example * * import PageTitle from "@bigbinary/neeto-molecules/PageTitle"; * * const Page = () => ( * * *
Page content
*
* ); * @endexample */ export const PageTitle: React.FC<{ title?: string; }>; /** * * The useIsElementVisibleInDom hook is a utility that allows you to determine * * whether a target element is currently visible within the viewport or intersects * * with an ancestor element. In simpler terms, it helps you know when a specified * * element is scrolled out of or scrolled into the screen's visible area. * * The following code snippet demonstrates the usage of useIsElementVisibleInDom * * to display the heading element. * * @example * * import { useIsElementVisibleInDom } from "@bigbinary/neeto-commons-frontend/react-utils"; * * const ref = useRef(null); * const isHeadingWrapperVisible = useIsElementVisibleInDom(ref.current, { * threshold: 0.5, * }); * * return ( *
*
*

Scroll down to next section

*
*
* {isHeadingWrapperVisible &&

Hello I'm on the screen

} *
*
* ); * @endexample * The hook watches for changes in the visibility of the referenced div element * * and provides a boolean value that you can use to conditionally render the header * * element with the text Hello I'm on the screen. * */ export function useIsElementVisibleInDom(target: Element | null, options?: OptionsType): Boolean; /** * * The useDebounce hook is a utility that allows you to wrap around a frequently * * updating state to retrieve the previous value until the updates are halted. This * * is particularly useful when you want to limit the number of API calls triggered * * by user inputs, such as a search box. The value returned by this hook will only * * reflect the latest value when the hook has not been called for the specified * * time period delay. * * The following code snippet demonstrates the usage of useDebounce in a search * * feature. * * @example * * import { useDebounce } from "@bigbinary/neeto-commons-frontend/react-utils"; * * const [searchKey, setSearchKey] = useState(""); * const debouncedSearchKey = useDebounce(searchKey, 300); * * useEffect(() => { * // will be triggered with the latest value of input * // only after 300ms after the user stops typing * }, [debouncedSearchKey]); * * // component * setSearchKey(e.target.value)} />; * @endexample * In the case of a search box, implemented without debouncing, every keystroke * * typically triggers a search query to find matching results. However, this rapid * * succession of queries can lead to several issues like performance overhead, poor * * user experience and inefficient resource usage. * * The useDebounce hook elegantly solves these problems by delaying the execution * * of the search function until the user pauses typing for a specified duration. * * This ensures that only one API request is made for the entire search operation, * * which solves all the issues mentioned earlier. * * You can learn more about the concept of debouncing * * here. * */ export function useDebounce(value: T, delay?: number): T; /** * * The useFuncDebounce hook is a utility that extends the benefits of debouncing * * to functions. * * When the debounced function is called, it sets a timer to execute the original * * function after a specified delay. If the debounced function is called again * * before the timer expires, the previous timer is cleared. This effectively delays * * the execution of the original function until the debounced function hasn't been * * called for the specified delay period. * * The hook also provides a cancel method to manually cancel the execution of the * * debounced function before it triggers. * * The following code snippet demonstrates the usage of useFuncDebounce in the * * delaying the invocation of the fetch method until the user pauses typing for a * * specific period. * * @example * * import { useFuncDebounce } from "@bigbinary/neeto-commons-frontend/react-utils"; * * const searchForProducts = useFuncDebounce(async key => { * // this function will be triggered once after user stops typing for 300ms * const products = await productsApi.fetch(key); * // do something with the products * }, 300); * * // component * searchForProducts(e.target.value)} />; * ; * @endexample */ export function useFuncDebounce(func: F, delay?: number): F & { cancel: () => void; }; /** * * The useLocalStorage hook is a utility for synchronizing and persisting state * * in the local storage of a web browser. It allows you to maintain data across * * page refreshes or even when the user navigates away from the page. This is * * useful for storing user preferences, settings, or any other data that should * * persist between sessions. * * To remove the value from local storage we can call the setter method with null * * or undefined. * * Note: Use this hook only if you need the component to re-render while * * updating the local storage value. If all you need is plain read and write * * operations on the localStorage, prefer the vanilla localStorage API functions. * * This hook will return an array with exactly two values just like useState * * hook. * * The following code snippet illustrates the usage of useLocalStorage in * * implementing a theme-switching feature. * * @example * * import { useLocalStorage } from "@bigbinary/neeto-commons-frontend/react-utils"; * * // here "theme" is the storage key and "light" is the initial value * const [theme, setTheme] = useLocalStorage("theme", "light"); * * return ( * setHiddenColumns(append(option.value))} * /> * ); * @endexample */ export function useLocalStorage(key: string, initialValue?: T): [T, (value: T) => void]; /** * * The useOnClickOutside hook is a useful utility for detecting clicks that occur * * outside of a specified element. It provides an elegant way to handle scenarios * * where you want to close or perform specific actions when a user clicks outside * * of a particular component, such as a modal dialog. * * The following code snippet demonstrates the usage of useOnClickOutside to * * detect clicks outside of a dropdown element and conditionally render the * * options. * * @example * * import { useOnClickOutside } from "@bigbinary/neeto-commons-frontend/react-utils"; * * const Dropdown = () => { * const dropdownRef = useRef(null); * const [isDropdownOpen, setIsDropdownOpen] = useState(false); * * // Use the useOnClickOutside hook to close the dropdown when clicking outside of it * useOnClickOutside(dropdownRef, () => setIsDropdownOpen(false)); * * return ( *
* * {isDropdownOpen && ( *
    *
  • Option 1
  • *
  • Option 2
  • *
  • Option 3
  • *
* )} *
* ); * }; * @endexample */ export function useOnClickOutside(ref: React.MutableRefObject, handler: (event: MouseEvent | TouchEvent) => any, options: { enabled: boolean; }); /** * * The usePrevious hook is a convenient utility to track the previous value of * * its argument before its most recent update. When it is called for the first * * time, it returns the initial value passed as an argument, and subsequently, it * * returns the previous value every time the component re-renders. * * The hook can be useful in monitoring modifications to form fields, such as * * detecting when fields become dirty, and taking action based on these * * alterations. * * The following code snippet illustrates the usage of usePrevious in tracking * * which fields were modified in a form. By comparing the current and previous * * values of form fields, you can easily identify and handle changes without the * * need for complex state management. * * @example * * import { usePrevious } from "@bigbinary/neeto-commons-frontend/react-utils"; * * // Initialize state for a form field (e.g., an input field) * const [name, setName] = useState(""); * * // Use the usePrevious hook to obtain the previous value of name * const previousName = usePrevious(name); * * // Use useEffect to detect changes in the 'name' field * useEffect(() => { * // Check if the 'name' field has changed * if (name !== previousName) { * // The 'name' field has been modified * // You can perform actions here, such as marking it as 'dirty' * // or updating other parts of your application * } * }, [name]); * @endexample * In the example, the useEffect block listens for changes in the name field. * * When the name field is updated, it compares the current value to the previous * * value. If they differ, it signifies that the field has been modified, enabling * * you to take appropriate actions. * */ export function usePrevious(value: T): T; /** * * The useUpdateEffect hook is a variation of the standard useEffect hook in * * React. The key difference is that useUpdateEffect does not execute the * * provided callback during the initial component mount. Instead, it only triggers * * the callback when the specified dependencies change. This behavior can be * * advantageous when you want to perform actions or side effects in response to * * changes in specific variables after the initial rendering of your component. * * The following code snippet shows the usage of useUpdateEffect in displaying * * category when its value is modified. * * @example * * import { useUpdateEffect } from "@bigbinary/neeto-commons-frontend/react-utils"; * * // Initialize state variables * const [category, setCategory] = useState("default"); * * // Use useUpdateEffect to update content based on category changes * useUpdateEffect(() => { * // This callback will run when 'category' changes, but not during the initial mount * console.log(`Category has been modified to ${category}`); * }, [category]); * @endexample * The useUpdateEffect hook allows you to specify a callback function that will * * only execute when certain dependencies, in this case, the category state, * * change after the initial mount. * */ export function useUpdateEffect(effect: () => void, deps: any[]): void; /** * * The useDisplayErrorPage hook is a utility that allows you to conditionally * * render an error page in your application based on the status codes of API * * responses. * * The following code snippet demonstrates the usage of useDisplayErrorPage in * * conditionally rendering an error page. * * @example * * import { useDisplayErrorPage } from "@bigbinary/neeto-commons-frontend/react-utils"; * * const App = () => { * const isError = useDisplayErrorPage(); * * if (isError) { * return ; * } * * return
; * }; * @endexample */ export function useDisplayErrorPage(): boolean; /** * * A Zustand store containing the status code of the latest API failed with 403 or * * 404 status. It stores the following values: * * This store is automatically managed by neeto-commons-frontend using its axios * * interceptors. You can also use this store if you need to display an error page * * from your frontend logic. * */ export const useErrorDisplayStore: UseBoundStore>; type TimerType = { lastUpdated: number; interval: number; }; /** * * The useTimer hook is a utility that enables automatic re-renders of a * * component at specified time intervals. This functionality is particularly useful * * for updating rendered content, such as elapsed time, without requiring manual * * refreshes. * * All invocations of useTimer hooks are attached to a single setInterval call * * which ticks every 1 second. So using that hook in multiple components won't * * cause any performance drop. * * Note that the maximum precision for useTimer hook is one second. In other * * words, there is a possibility that your component will take at most one more * * second than the scheduled time interval to re-render. * * The following demonstrates the usage of useTimer hook in displaying * * time-sensitive information. * * @example * * import { useTimer } from "@bigbinary/neeto-commons-frontend/react-utils"; * * const Post = () => { * // Use the useTimer hook with a custom interval * useTimer(30); * * // Calculate the elapsed time since the post creation * const currentTime = new Date(); * const elapsedTimeInSeconds = Math.floor((currentTime - createdAt) / 1000); * * return

Elapsed Time in seconds: {elapsedTimeInSeconds}

; * }; * @endexample */ export function useTimer(interval: number): TimerType; type ZustandConfigType = (set: (data: any) => void, get: () => any, api: any) => any; /** * * withImmutableActions is a Zustand middleware function that prevents the * * actions from getting overwritten. * * @example * * const useStore = create( * withImmutableActions(set => ({ * value: 10, * // other properties ... * setValue: ({ value }) => set({ value }), * setGlobalState: set, * // other actions ... * })) * ); * @endexample * In the example above, any attempts like the following will trigger an error * * because actions should never be overwritten: * * @example * * setGlobalState({ value: 0, setValue: () => {} }); * @endexample * However, actions can be assigned their own values. This enables you to use * * curried Ramda functions in conjunction with Zustand actions. For instance, the * * following usage will not result in an error: * * @example * * setGlobalState(state => ({ value: 0, setValue: state.setValue })); * @endexample * The second parameter to overwrite the entire state will be ignored. Both of the * * following lines of code are functionally equivalent: * * @example * * setGlobalState(state => ({ value: 0 }), true); * setGlobalState(state => ({ value: 0 })); * @endexample * It should be noted that the withImmutableActions middleware intercepts and * * wraps the set method of the Zustand store to enforce immutability rules. * * Therefore, usages of useStore.setState() won't be handled by the middleware * * since they directly update the state in Zustand without going through the set * * method of the store. * * @example * * // This won't be handled by the middleware. * useStore.setState({ value: 0, setValue: () => {} }); * @endexample */ export function withImmutableActions(config: ZustandConfigType): ZustandConfigType; export declare type ZustandStoreHook = UseBoundStore> & { pick: (path?: string | string[]) => any; }; /** * * The useFieldSubmit hook simplifies the task of capturing the Enter * * (Return) key press event within an input field and executing a callback * * function when the Enter key is pressed. This is a common requirement in forms * * where pressing Enter should trigger specific actions, such as submitting a * * form or processing user input. Importantly, this hook ensures that pressing * * Shift + Enter does not trigger the callback, allowing for the creation of * * multi-line text inputs. * * The following code snippet illustrates the usage of useFieldSubmit in building * * an interactive textarea input field. * * @example * * import { useFieldSubmit } from "@bigbinary/neeto-commons-frontend/react-utils"; * * // Create a ref for the input field using useFieldSubmit * const inputRef = useFieldSubmit(() => { * const inputValue = inputRef.current.value; * console.log(inputValue); * }); * * return