@bigbinary/neeto-commons-frontend 4.2.0 → 4.3.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/cjs/react-utils/AppContainer/AppContainer.js +53 -0
  2. package/cjs/react-utils/AppContainer/AppContainer.js.map +1 -0
  3. package/cjs/react-utils/AppContainer/index.js +14 -0
  4. package/cjs/react-utils/AppContainer/index.js.map +1 -0
  5. package/cjs/react-utils/QueryClientProvider/QueryClientProvider.js +21 -0
  6. package/cjs/react-utils/QueryClientProvider/QueryClientProvider.js.map +1 -0
  7. package/cjs/react-utils/QueryClientProvider/index.js +21 -0
  8. package/cjs/react-utils/QueryClientProvider/index.js.map +1 -0
  9. package/cjs/react-utils/QueryClientProvider/queryClient.js +23 -0
  10. package/cjs/react-utils/QueryClientProvider/queryClient.js.map +1 -0
  11. package/cjs/react-utils/index.js +28 -1
  12. package/cjs/react-utils/index.js.map +1 -1
  13. package/package.json +3 -1
  14. package/react-utils/AppContainer/AppContainer.js +43 -0
  15. package/react-utils/AppContainer/AppContainer.js.map +1 -0
  16. package/react-utils/AppContainer/index.js +1 -0
  17. package/react-utils/AppContainer/index.js.map +1 -0
  18. package/react-utils/QueryClientProvider/QueryClientProvider.js +13 -0
  19. package/react-utils/QueryClientProvider/QueryClientProvider.js.map +1 -0
  20. package/react-utils/QueryClientProvider/index.js +3 -0
  21. package/react-utils/QueryClientProvider/index.js.map +1 -0
  22. package/react-utils/QueryClientProvider/queryClient.js +16 -0
  23. package/react-utils/QueryClientProvider/queryClient.js.map +1 -0
  24. package/react-utils/index.js +3 -0
  25. package/react-utils/index.js.map +1 -1
  26. package/react-utils.d.ts +177 -1675
  27. package/utils.d.ts +95 -570
package/react-utils.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import React, { ComponentType, ElementType, ReactNode } from "react";
2
- import { RouteProps } from "react-router-dom";
2
+
3
+ import { RouteProps, BrowserSupport } from "react-router-dom";
3
4
  import { Notice } from "@honeybadger-io/js/dist/server/types/core/types";
4
5
  import { History } from "history";
5
6
  import { StoreApi, UseBoundStore } from "zustand";
@@ -8,1723 +9,224 @@ import { KeyPrefix, Namespace } from "i18next";
8
9
  import { DefaultNamespace } from "react-i18next/TransWithoutContext";
9
10
  import { qsOptionsType, QueryParamsType } from "./utils";
10
11
  import { QueryFilters } from "react-query/types/core/utils";
11
- /**
12
- *
13
- * The HoneybadgerErrorBoundary is an ErrorBoundary which reports frontend errors
14
- *
15
- * to HoneyBadger.
16
- *
17
- * This component will wrap its children with the error boundary provided by
18
- *
19
- * @honeybadger-io/react package. In this component, we will create a honeybadger
20
- *
21
- * configuration object using the API key, environment and project version which we
22
- *
23
- * obtained from the globalProps and pass the created object to error boundary
24
- *
25
- * provided by honeybadger. We are also filtering the false-positive errors using
26
- *
27
- * beforeNotify method.
28
- *
29
- * For global error handling, we need to wrap the Main component with this
30
- *
31
- * HoneybadgerErrorBoundary component as shown below.
32
- *
33
- * @example
34
- *
35
- * <HoneybadgerErrorBoundary
36
- * ErrorComponent={ErrorComponent}
37
- * filterErrors={notice => !/IgnorableError/.test(notice.message)}
38
- * >
39
- * <Main />
40
- * </HoneybadgerErrorBoundary>
41
- * @endexample
42
- * ErrorComponent is the component which will be rendered when an error is thrown
43
- *
44
- * during rendering. This is an optional prop and if this prop is not provided then
45
- *
46
- * honeybadger will use DefaultErrorComponent for fallback UI.
47
- *
48
- * filterErrors is a function which takes the honeybadger notice as argument and
49
- *
50
- * returns a boolean. It should return true if the error is to be reported and
51
- *
52
- * false if not.
53
- *
54
- */
55
- export const HoneybadgerErrorBoundary: React.FC<{
12
+ import BrowserSupport from "@bigbinary/neeto-molecules/types/BrowserSupport";
13
+
14
+ type HoneybadgerErrorBoundaryPropsType = {
56
15
  ErrorComponent?: ReactNode | ComponentType | ElementType;
57
16
  filterErrors?: (error: Notice) => boolean;
58
17
  children?: ReactNode;
18
+ }
19
+ type BrowserSupportPropsType = React.ComponentProps<typeof BrowserSupport>;
20
+ export const HoneybadgerErrorBoundary: React.FC<HoneybadgerErrorBoundaryPropsType>;
21
+ export const QueryClientProvider: React.FC<{
22
+ children?: ReactNode;
23
+ }>;
24
+ export const AppContainer: React.FC<{
25
+ children?: ReactNode;
26
+ honeybadgerErrorBoundaryProps?: HoneybadgerErrorBoundaryPropsType;
27
+ browserSupportProps?: BrowserSupportPropsType;
28
+ reactQueryDevtoolsProps?: {
29
+ [key: string]: any;
30
+ };
31
+ toastContainerProps?: {
32
+ [key: string]: any;
33
+ };
34
+ enableStickyRibbons?: boolean;
59
35
  }>;
60
- /**
61
- *
62
- * PrivateRoute is a route that will restrict access to it based on a specified
63
- *
64
- * condition and permissions.
65
- *
66
- * If the given condition is true and the user has the required permissions, it
67
- *
68
- * acts identical to a normal route. If the condition is true and the user does not
69
- *
70
- * have the required permissions, it will show 403 error page or it will render a
71
- *
72
- * supplied error page. If the condition is false, it will redirect user to a
73
- *
74
- * different path if redirectRoute is specified or it will render a supplied error
75
- *
76
- * page.
77
- *
78
- * If condition is not specified, it will assume the value of
79
- *
80
- * globalProps.authenticated by default.
81
- *
82
- * Here are some example use cases:
83
- *
84
- */
85
- export function PrivateRoute(props: {
86
- condition?: boolean;
87
- redirectRoute?: string;
88
- errorPage?: React.ReactNode;
89
- permissions?: string[];
90
- } & RouteProps): JSX.Element;
36
+
37
+ export function PrivateRoute(
38
+ props: {
39
+ condition?: boolean;
40
+ redirectRoute?: string;
41
+ errorPage?: React.ReactNode;
42
+ permissions?: string[];
43
+ } & RouteProps
44
+ ): JSX.Element;
45
+
91
46
  type OptionsType = {
92
47
  root?: Element | null;
93
48
  rootMargin?: String;
94
49
  threshold?: Number | Number[];
95
50
  };
96
- /**
97
- *
98
- * Component to set the page title.
99
- *
100
- * @example
101
- *
102
- * import React from "react";
103
- * import PageTitle from "@bigbinary/neeto-molecules/PageTitle";
104
- *
105
- * const Page = () => (
106
- * <Container>
107
- * <PageTitle title="Login" />
108
- * <div>Page content</div>
109
- * </Container>
110
- * );
111
- * @endexample
112
- */
51
+
113
52
  export const PageTitle: React.FC<{
114
53
  title?: string;
115
54
  }>;
116
- /**
117
- *
118
- * The useIsElementVisibleInDom hook is a utility that allows you to determine
119
- *
120
- * whether a target element is currently visible within the viewport or intersects
121
- *
122
- * with an ancestor element. In simpler terms, it helps you know when a specified
123
- *
124
- * element is scrolled out of or scrolled into the screen's visible area.
125
- *
126
- * The following code snippet demonstrates the usage of useIsElementVisibleInDom
127
- *
128
- * to display the heading element.
129
- *
130
- * @example
131
- *
132
- * import { useIsElementVisibleInDom } from "@bigbinary/neeto-commons-frontend/react-utils";
133
- *
134
- * const ref = useRef(null);
135
- * const isHeadingWrapperVisible = useIsElementVisibleInDom(ref.current, {
136
- * threshold: 0.5,
137
- * });
138
- *
139
- * return (
140
- * <div>
141
- * <div style={{ height: "100vh" }}>
142
- * <h1>Scroll down to next section</h1>
143
- * </div>
144
- * <div ref={ref}>
145
- * {isHeadingWrapperVisible && <h1>Hello I'm on the screen</h1>}
146
- * </div>
147
- * </div>
148
- * );
149
- * @endexample
150
- * The hook watches for changes in the visibility of the referenced div element
151
- *
152
- * and provides a boolean value that you can use to conditionally render the header
153
- *
154
- * element with the text Hello I'm on the screen.
155
- *
156
- */
157
- export function useIsElementVisibleInDom(target: Element | null, options?: OptionsType): Boolean;
158
- /**
159
- *
160
- * The useDebounce hook is a utility that allows you to wrap around a frequently
161
- *
162
- * updating state to retrieve the previous value until the updates are halted. This
163
- *
164
- * is particularly useful when you want to limit the number of API calls triggered
165
- *
166
- * by user inputs, such as a search box. The value returned by this hook will only
167
- *
168
- * reflect the latest value when the hook has not been called for the specified
169
- *
170
- * time period delay.
171
- *
172
- * The following code snippet demonstrates the usage of useDebounce in a search
173
- *
174
- * feature.
175
- *
176
- * @example
177
- *
178
- * import { useDebounce } from "@bigbinary/neeto-commons-frontend/react-utils";
179
- *
180
- * const [searchKey, setSearchKey] = useState("");
181
- * const debouncedSearchKey = useDebounce(searchKey, 300);
182
- *
183
- * useEffect(() => {
184
- * // will be triggered with the latest value of input
185
- * // only after 300ms after the user stops typing
186
- * }, [debouncedSearchKey]);
187
- *
188
- * // component
189
- * <Input onChange={e => setSearchKey(e.target.value)} />;
190
- * @endexample
191
- * In the case of a search box, implemented without debouncing, every keystroke
192
- *
193
- * typically triggers a search query to find matching results. However, this rapid
194
- *
195
- * succession of queries can lead to several issues like performance overhead, poor
196
- *
197
- * user experience and inefficient resource usage.
198
- *
199
- * The useDebounce hook elegantly solves these problems by delaying the execution
200
- *
201
- * of the search function until the user pauses typing for a specified duration.
202
- *
203
- * This ensures that only one API request is made for the entire search operation,
204
- *
205
- * which solves all the issues mentioned earlier.
206
- *
207
- * You can learn more about the concept of debouncing
208
- *
209
- * here.
210
- *
211
- */
55
+
56
+ export function useIsElementVisibleInDom(
57
+ target: Element | null,
58
+ options?: OptionsType
59
+ ): Boolean;
60
+
212
61
  export function useDebounce<T>(value: T, delay?: number): T;
213
- /**
214
- *
215
- * The useFuncDebounce hook is a utility that extends the benefits of debouncing
216
- *
217
- * to functions.
218
- *
219
- * When the debounced function is called, it sets a timer to execute the original
220
- *
221
- * function after a specified delay. If the debounced function is called again
222
- *
223
- * before the timer expires, the previous timer is cleared. This effectively delays
224
- *
225
- * the execution of the original function until the debounced function hasn't been
226
- *
227
- * called for the specified delay period.
228
- *
229
- * The hook also provides a cancel method to manually cancel the execution of the
230
- *
231
- * debounced function before it triggers.
232
- *
233
- * The following code snippet demonstrates the usage of useFuncDebounce in the
234
- *
235
- * delaying the invocation of the fetch method until the user pauses typing for a
236
- *
237
- * specific period.
238
- *
239
- * @example
240
- *
241
- * import { useFuncDebounce } from "@bigbinary/neeto-commons-frontend/react-utils";
242
- *
243
- * const searchForProducts = useFuncDebounce(async key => {
244
- * // this function will be triggered once after user stops typing for 300ms
245
- * const products = await productsApi.fetch(key);
246
- * // do something with the products
247
- * }, 300);
248
- *
249
- * // component
250
- * <Input onChange={e => searchForProducts(e.target.value)} />;
251
- * <Button onClick={() => searchForProducts.cancel()}>Cancel search</Button>;
252
- * @endexample
253
- */
254
- export function useFuncDebounce<F extends Function>(func: F, delay?: number): F & {
255
- cancel: () => void;
256
- };
257
- /**
258
- *
259
- * The useLocalStorage hook is a utility for synchronizing and persisting state
260
- *
261
- * in the local storage of a web browser. It allows you to maintain data across
262
- *
263
- * page refreshes or even when the user navigates away from the page. This is
264
- *
265
- * useful for storing user preferences, settings, or any other data that should
266
- *
267
- * persist between sessions.
268
- *
269
- * To remove the value from local storage we can call the setter method with null
270
- *
271
- * or undefined.
272
- *
273
- * Note: Use this hook only if you need the component to re-render while
274
- *
275
- * updating the local storage value. If all you need is plain read and write
276
- *
277
- * operations on the localStorage, prefer the vanilla localStorage API functions.
278
- *
279
- * This hook will return an array with exactly two values just like useState
280
- *
281
- * hook.
282
- *
283
- * The following code snippet illustrates the usage of useLocalStorage in
284
- *
285
- * implementing a theme-switching feature.
286
- *
287
- * @example
288
- *
289
- * import { useLocalStorage } from "@bigbinary/neeto-commons-frontend/react-utils";
290
- *
291
- * // here "theme" is the storage key and "light" is the initial value
292
- * const [theme, setTheme] = useLocalStorage("theme", "light");
293
- *
294
- * return (
295
- * <Select
296
- * options={[
297
- * { label: "light", value: "light" },
298
- * { label: "dark", value: "dark" },
299
- * ]}
300
- * // when we change the theme, the same will be stored in local storage with the key "theme"
301
- * onChange={option => setTheme(option.value)}
302
- * />
303
- * );
304
- * @endexample
305
- * The initial value is used when the key is not found in local storage, ensuring
306
- *
307
- * that a default theme is applied when the user first visits the site. Subsequent
308
- *
309
- * changes to the theme are automatically synchronized with local storage.
310
- *
311
- * The following code snippet illustrates how we can pass a function to the
312
- *
313
- * setValue method of useLocalStorage
314
- *
315
- * @example
316
- *
317
- * import { useLocalStorage } from "@bigbinary/neeto-commons-frontend/react-utils";
318
- * import { append } from "ramda";
319
- *
320
- * // here "hiddenColumns" is the storage key and "[]" is the initial value
321
- * const [hiddenColumns, setHiddenColumns] = useLocalStorage("hiddenColumns", []);
322
- *
323
- * return (
324
- * <Select
325
- * options={[
326
- * { label: "Name", value: "name" },
327
- * { label: "Created at", value: "created_at" },
328
- * ]}
329
- * // when a new column to hide is selected, the same will be appended to the existing list of hidden columns and stored in local storage with the key "hiddenColumns"
330
- * onChange={option => setHiddenColumns(append(option.value))}
331
- * />
332
- * );
333
- * @endexample
334
- */
335
- export function useLocalStorage<T>(key: string, initialValue?: T): [T, (value: T) => void];
336
- /**
337
- *
338
- * The useOnClickOutside hook is a useful utility for detecting clicks that occur
339
- *
340
- * outside of a specified element. It provides an elegant way to handle scenarios
341
- *
342
- * where you want to close or perform specific actions when a user clicks outside
343
- *
344
- * of a particular component, such as a modal dialog.
345
- *
346
- * The following code snippet demonstrates the usage of useOnClickOutside to
347
- *
348
- * detect clicks outside of a dropdown element and conditionally render the
349
- *
350
- * options.
351
- *
352
- * @example
353
- *
354
- * import { useOnClickOutside } from "@bigbinary/neeto-commons-frontend/react-utils";
355
- *
356
- * const Dropdown = () => {
357
- * const dropdownRef = useRef(null);
358
- * const [isDropdownOpen, setIsDropdownOpen] = useState(false);
359
- *
360
- * // Use the useOnClickOutside hook to close the dropdown when clicking outside of it
361
- * useOnClickOutside(dropdownRef, () => setIsDropdownOpen(false));
362
- *
363
- * return (
364
- * <div className="dropdown" ref={dropdownRef}>
365
- * <button onClick={() => setIsDropdownOpen(!isDropdownOpen)}>
366
- * Toggle Dropdown
367
- * </button>
368
- * {isDropdownOpen && (
369
- * <ul className="dropdown-menu">
370
- * <li>Option 1</li>
371
- * <li>Option 2</li>
372
- * <li>Option 3</li>
373
- * </ul>
374
- * )}
375
- * </div>
376
- * );
377
- * };
378
- * @endexample
379
- */
380
- export function useOnClickOutside<T>(ref: React.MutableRefObject<T>, handler: (event: MouseEvent | TouchEvent) => any, options: {
381
- enabled: boolean;
382
- });
383
- /**
384
- *
385
- * The usePrevious hook is a convenient utility to track the previous value of
386
- *
387
- * its argument before its most recent update. When it is called for the first
388
- *
389
- * time, it returns the initial value passed as an argument, and subsequently, it
390
- *
391
- * returns the previous value every time the component re-renders.
392
- *
393
- * The hook can be useful in monitoring modifications to form fields, such as
394
- *
395
- * detecting when fields become dirty, and taking action based on these
396
- *
397
- * alterations.
398
- *
399
- * The following code snippet illustrates the usage of usePrevious in tracking
400
- *
401
- * which fields were modified in a form. By comparing the current and previous
402
- *
403
- * values of form fields, you can easily identify and handle changes without the
404
- *
405
- * need for complex state management.
406
- *
407
- * @example
408
- *
409
- * import { usePrevious } from "@bigbinary/neeto-commons-frontend/react-utils";
410
- *
411
- * // Initialize state for a form field (e.g., an input field)
412
- * const [name, setName] = useState("");
413
- *
414
- * // Use the usePrevious hook to obtain the previous value of name
415
- * const previousName = usePrevious(name);
416
- *
417
- * // Use useEffect to detect changes in the 'name' field
418
- * useEffect(() => {
419
- * // Check if the 'name' field has changed
420
- * if (name !== previousName) {
421
- * // The 'name' field has been modified
422
- * // You can perform actions here, such as marking it as 'dirty'
423
- * // or updating other parts of your application
424
- * }
425
- * }, [name]);
426
- * @endexample
427
- * In the example, the useEffect block listens for changes in the name field.
428
- *
429
- * When the name field is updated, it compares the current value to the previous
430
- *
431
- * value. If they differ, it signifies that the field has been modified, enabling
432
- *
433
- * you to take appropriate actions.
434
- *
435
- */
62
+
63
+ export function useFuncDebounce<F extends Function>(
64
+ func: F,
65
+ delay?: number
66
+ ): F & { cancel: () => void };
67
+
68
+ export function useLocalStorage<T>(
69
+ key: string,
70
+ initialValue?: T
71
+ ): [T, (value: T) => void];
72
+
73
+ export function useOnClickOutside<T>(
74
+ ref: React.MutableRefObject<T>,
75
+ handler: (event: MouseEvent | TouchEvent) => any,
76
+ options: { enabled: boolean }
77
+ );
78
+
436
79
  export function usePrevious<T>(value: T): T;
437
- /**
438
- *
439
- * The useUpdateEffect hook is a variation of the standard useEffect hook in
440
- *
441
- * React. The key difference is that useUpdateEffect does not execute the
442
- *
443
- * provided callback during the initial component mount. Instead, it only triggers
444
- *
445
- * the callback when the specified dependencies change. This behavior can be
446
- *
447
- * advantageous when you want to perform actions or side effects in response to
448
- *
449
- * changes in specific variables after the initial rendering of your component.
450
- *
451
- * The following code snippet shows the usage of useUpdateEffect in displaying
452
- *
453
- * category when its value is modified.
454
- *
455
- * @example
456
- *
457
- * import { useUpdateEffect } from "@bigbinary/neeto-commons-frontend/react-utils";
458
- *
459
- * // Initialize state variables
460
- * const [category, setCategory] = useState("default");
461
- *
462
- * // Use useUpdateEffect to update content based on category changes
463
- * useUpdateEffect(() => {
464
- * // This callback will run when 'category' changes, but not during the initial mount
465
- * console.log(`Category has been modified to ${category}`);
466
- * }, [category]);
467
- * @endexample
468
- * The useUpdateEffect hook allows you to specify a callback function that will
469
- *
470
- * only execute when certain dependencies, in this case, the category state,
471
- *
472
- * change after the initial mount.
473
- *
474
- */
80
+
475
81
  export function useUpdateEffect(effect: () => void, deps: any[]): void;
476
- /**
477
- *
478
- * The useDisplayErrorPage hook is a utility that allows you to conditionally
479
- *
480
- * render an error page in your application based on the status codes of API
481
- *
482
- * responses.
483
- *
484
- * The following code snippet demonstrates the usage of useDisplayErrorPage in
485
- *
486
- * conditionally rendering an error page.
487
- *
488
- * @example
489
- *
490
- * import { useDisplayErrorPage } from "@bigbinary/neeto-commons-frontend/react-utils";
491
- *
492
- * const App = () => {
493
- * const isError = useDisplayErrorPage();
494
- *
495
- * if (isError) {
496
- * return <ErrorPage />;
497
- * }
498
- *
499
- * return <Main />;
500
- * };
501
- * @endexample
502
- */
82
+
503
83
  export function useDisplayErrorPage(): boolean;
504
- /**
505
- *
506
- * A Zustand store containing the status code of the latest API failed with 403 or
507
- *
508
- * 404 status. It stores the following values:
509
- *
510
- * This store is automatically managed by neeto-commons-frontend using its axios
511
- *
512
- * interceptors. You can also use this store if you need to display an error page
513
- *
514
- * from your frontend logic.
515
- *
516
- */
517
- export const useErrorDisplayStore: UseBoundStore<StoreApi<{
518
- showErrorPage: boolean;
519
- statusCode: number;
520
- failedApiUrl: string;
521
- failedApiPath: string;
522
- }>>;
84
+
85
+ export const useErrorDisplayStore: UseBoundStore<
86
+ StoreApi<{
87
+ showErrorPage: boolean;
88
+ statusCode: number;
89
+ failedApiUrl: string;
90
+ failedApiPath: string;
91
+ }>
92
+ >;
93
+
523
94
  type TimerType = {
524
95
  lastUpdated: number;
525
96
  interval: number;
526
97
  };
527
- /**
528
- *
529
- * The useTimer hook is a utility that enables automatic re-renders of a
530
- *
531
- * component at specified time intervals. This functionality is particularly useful
532
- *
533
- * for updating rendered content, such as elapsed time, without requiring manual
534
- *
535
- * refreshes.
536
- *
537
- * All invocations of useTimer hooks are attached to a single setInterval call
538
- *
539
- * which ticks every 1 second. So using that hook in multiple components won't
540
- *
541
- * cause any performance drop.
542
- *
543
- * Note that the maximum precision for useTimer hook is one second. In other
544
- *
545
- * words, there is a possibility that your component will take at most one more
546
- *
547
- * second than the scheduled time interval to re-render.
548
- *
549
- * The following demonstrates the usage of useTimer hook in displaying
550
- *
551
- * time-sensitive information.
552
- *
553
- * @example
554
- *
555
- * import { useTimer } from "@bigbinary/neeto-commons-frontend/react-utils";
556
- *
557
- * const Post = () => {
558
- * // Use the useTimer hook with a custom interval
559
- * useTimer(30);
560
- *
561
- * // Calculate the elapsed time since the post creation
562
- * const currentTime = new Date();
563
- * const elapsedTimeInSeconds = Math.floor((currentTime - createdAt) / 1000);
564
- *
565
- * return <p>Elapsed Time in seconds: {elapsedTimeInSeconds}</p>;
566
- * };
567
- * @endexample
568
- */
569
98
  export function useTimer(interval: number): TimerType;
570
- type ZustandConfigType = (set: (data: any) => void, get: () => any, api: any) => any;
571
- /**
572
- *
573
- * withImmutableActions is a Zustand middleware function that prevents the
574
- *
575
- * actions from getting overwritten.
576
- *
577
- * @example
578
- *
579
- * const useStore = create(
580
- * withImmutableActions(set => ({
581
- * value: 10,
582
- * // other properties ...
583
- * setValue: ({ value }) => set({ value }),
584
- * setGlobalState: set,
585
- * // other actions ...
586
- * }))
587
- * );
588
- * @endexample
589
- * In the example above, any attempts like the following will trigger an error
590
- *
591
- * because actions should never be overwritten:
592
- *
593
- * @example
594
- *
595
- * setGlobalState({ value: 0, setValue: () => {} });
596
- * @endexample
597
- * However, actions can be assigned their own values. This enables you to use
598
- *
599
- * curried Ramda functions in conjunction with Zustand actions. For instance, the
600
- *
601
- * following usage will not result in an error:
602
- *
603
- * @example
604
- *
605
- * setGlobalState(state => ({ value: 0, setValue: state.setValue }));
606
- * @endexample
607
- * The second parameter to overwrite the entire state will be ignored. Both of the
608
- *
609
- * following lines of code are functionally equivalent:
610
- *
611
- * @example
612
- *
613
- * setGlobalState(state => ({ value: 0 }), true);
614
- * setGlobalState(state => ({ value: 0 }));
615
- * @endexample
616
- * It should be noted that the withImmutableActions middleware intercepts and
617
- *
618
- * wraps the set method of the Zustand store to enforce immutability rules.
619
- *
620
- * Therefore, usages of useStore.setState() won't be handled by the middleware
621
- *
622
- * since they directly update the state in Zustand without going through the set
623
- *
624
- * method of the store.
625
- *
626
- * @example
627
- *
628
- * // This won't be handled by the middleware.
629
- * useStore.setState({ value: 0, setValue: () => {} });
630
- * @endexample
631
- */
632
- export function withImmutableActions(config: ZustandConfigType): ZustandConfigType;
99
+
100
+ type ZustandConfigType = (
101
+ set: (data: any) => void,
102
+ get: () => any,
103
+ api: any
104
+ ) => any;
105
+ export function withImmutableActions(
106
+ config: ZustandConfigType
107
+ ): ZustandConfigType;
108
+
633
109
  export declare type ZustandStoreHook = UseBoundStore<StoreApi<any>> & {
634
110
  pick: (path?: string | string[]) => any;
635
111
  };
636
- /**
637
- *
638
- * The useFieldSubmit hook simplifies the task of capturing the Enter
639
- *
640
- * (Return) key press event within an input field and executing a callback
641
- *
642
- * function when the Enter key is pressed. This is a common requirement in forms
643
- *
644
- * where pressing Enter should trigger specific actions, such as submitting a
645
- *
646
- * form or processing user input. Importantly, this hook ensures that pressing
647
- *
648
- * Shift + Enter does not trigger the callback, allowing for the creation of
649
- *
650
- * multi-line text inputs.
651
- *
652
- * The following code snippet illustrates the usage of useFieldSubmit in building
653
- *
654
- * an interactive textarea input field.
655
- *
656
- * @example
657
- *
658
- * import { useFieldSubmit } from "@bigbinary/neeto-commons-frontend/react-utils";
659
- *
660
- * // Create a ref for the input field using useFieldSubmit
661
- * const inputRef = useFieldSubmit(() => {
662
- * const inputValue = inputRef.current.value;
663
- * console.log(inputValue);
664
- * });
665
- *
666
- * return <textarea ref={inputRef} />;
667
- * @endexample
668
- * When the Enter key is pressed, the onSubmit callback function is executed,
669
- *
670
- * allowing you to access the input value and perform the desired action.
671
- *
672
- */
112
+
673
113
  export function useFieldSubmit(onSubmit: () => any): {
674
114
  current: HTMLInputElement & HTMLTextAreaElement;
675
115
  };
676
- /**
677
- *
678
- * withTitle is an HOC which sets the browser title with the given value when the
679
- *
680
- * wrapped component is rendered. If title is not explicitly provided, it will
681
- *
682
- * render globalProps.appName as the page title.
683
- *
684
- * @example
685
- *
686
- * // assume this code in neetoStore
687
- * const ProductsPage = props => <>Your page content here</>;
688
- *
689
- * // will set the browser title to `All products | neetoStore` when this page is rendered.
690
- * export default withTitle(ProductsPage, "All products");
691
- * @endexample
692
- */
693
- export function withTitle<T>(Component: React.ComponentType<T>, title?: string | null): (props: T) => JSX.Element;
694
- /**
695
- *
696
- * registerBrowserNotifications is a browser push notifications utility function
697
- *
698
- * which asks the user permissions to send notifications and then register the
699
- *
700
- * browser with the notification service.
701
- *
702
- * To enable the notification service to dispatch web push messages to browsers, it
703
- *
704
- * relies on VAPID keys. These
705
- *
706
- * keys should be securely stored as environment variables and made accessible
707
- *
708
- * through process.env. If keys are not accessible from process.env, pass in
709
- *
710
- * the vapidPublicKey using global props from application helper.
711
- *
712
- * You can find the VAPID keys (PUBLIC and PRIVATE) for neeto products at
713
- *
714
- * neetoNotifications Dashboard.
715
- *
716
- * After the user logs in, we need to ask the user permissions to send
717
- *
718
- * notifications and then register the browser with the notification service. The
719
- *
720
- * registerBrowserNotifications utility function facilitates this process. It can
721
- *
722
- * be called on any event after login based on the application's logic and
723
- *
724
- * requirement.
725
- *
726
- * Here as an example, we are calling registerBrowserNotifications method inside
727
- *
728
- * the Login component after the Authentication API request. This helps to
729
- *
730
- * associate the browser for that particular user.
731
- *
732
- * @example
733
- *
734
- * import { registerBrowserNotifications } from "neetocommons/react-utils";
735
- *
736
- * const handleLogin = async () => {
737
- * try {
738
- * // Authentication API request
739
- * await registerBrowserNotifications();
740
- * history.push(DASHBOARD_URL);
741
- * } catch {}
742
- * };
743
- * @endexample
744
- * The above mentioned feature is currently supported for chromium-based browsers.
745
- *
746
- * Safari (iOS) is currently WIP.
747
- *
748
- * Any other browser which is not mentioned in above will be considered as
749
- *
750
- * unsupported.
751
- *
752
- */
116
+
117
+ export function withTitle<T>(
118
+ Component: React.ComponentType<T>,
119
+ title?: string | null
120
+ ): (props: T) => JSX.Element;
121
+
753
122
  export async function registerBrowserNotifications(): Promise<void>;
754
- /**
755
- *
756
- * destroyBrowserSubscription is a browser push notifications utility function
757
- *
758
- * which destroys the browser subscriptions from the user's devices. This helps in
759
- *
760
- * unsubscribing from browser push notifications.
761
- *
762
- * When the browser subscriptions expires for the user's devices or when the user
763
- *
764
- * decides to logout, the generated browser subscription for the user should be
765
- *
766
- * destroyed. The destroyBrowserSubscription utility function enables us to do
767
- *
768
- * the same. It can be called on any event before logout based on the application's
769
- *
770
- * logic and requirement.
771
- *
772
- * Here is an example: In the Logout component, we are calling
773
- *
774
- * destroyBrowserSubscription method before the Logout API request. This
775
- *
776
- * helps to destroy the browser subscription from the user's devices.
777
- *
778
- * @example
779
- *
780
- * import { destroyBrowserSubscription } from "neetocommons/react-utils";
781
- *
782
- * const handleLogout = async () => {
783
- * try {
784
- * await destroyBrowserSubscription(); //Before logout request
785
- * // Logout API request
786
- * window.location.href = LOGIN_PATH;
787
- * } catch {}
788
- * };
789
- * @endexample
790
- * The above mentioned feature is currently supported for chromium-based browsers.
791
- *
792
- * Safari (iOS) is currently WIP.
793
- *
794
- * Any other browser which is not mentioned in above will be considered as
795
- *
796
- * unsupported.
797
- *
798
- */
123
+
799
124
  export async function destroyBrowserSubscription(): Promise<void>;
125
+
800
126
  type handleMetaClickOptions = {
801
- isHistoryReplace?: boolean;
802
- };
803
- /**
804
- *
805
- * The handleMetaClick function can be used to handle onClick actions that
806
- *
807
- * redirects to a URL. It opens up the URL in a new tab if ctrl/cmd + click event
808
- *
809
- * is received. Otherwise, simply redirects to the provided URL in the same tab.
810
- *
811
- * URL can be passed as string or a history location object can be passed instead.
812
- *
813
- * Let's say you have a navigation menu with several links, and you want to allow
814
- *
815
- * users to open these links in a new tab if they hold down the Ctrl (or Cmd on
816
- *
817
- * macOS) key while clicking, and if they click without holding down the Ctrl key,
818
- *
819
- * the link should open in the same tab. You can use handleMetaClick to achieve
820
- *
821
- * this behavior.
822
- *
823
- * @example
824
- *
825
- * const NavigationMenu = () => {
826
- * const history = useHistory();
827
- *
828
- * const handleLinkClick = (url, event) => {
829
- * // Opens url in a new tab if metaKey/CtrlKey is pressed.
830
- * // Otherwise simply redirects to url.
831
- * handleMetaClick(history, url, event);
832
- * };
833
- *
834
- * return (
835
- * <div>
836
- * <a href="/home" onClick={e => handleLinkClick("/home", e)}>
837
- * Home
838
- * </a>
839
- * <a href="/dashboard" onClick={e => handleLinkClick("/dashboard", e)}>
840
- * Dashboard
841
- * </a>
842
- * <a href="/profile" onClick={e => handleLinkClick("/profile", e)}>
843
- * Profile
844
- * </a>
845
- * </div>
846
- * );
847
- * };
848
- * @endexample
849
- */
850
- export function handleMetaClick(history: History, params: string | object, event: React.MouseEvent<HTMLElement, MouseEvent>, options?: handleMetaClickOptions): void;
851
- /**
852
- *
853
- * The handleMetaClick function can be used to handle onClick actions that
854
- *
855
- * redirects to a URL. It opens up the URL in a new tab if ctrl/cmd + click event
856
- *
857
- * is received. Otherwise, simply redirects to the provided URL in the same tab.
858
- *
859
- * URL can be passed as string or a history location object can be passed instead.
860
- *
861
- * Let's say you have a navigation menu with several links, and you want to allow
862
- *
863
- * users to open these links in a new tab if they hold down the Ctrl (or Cmd on
864
- *
865
- * macOS) key while clicking, and if they click without holding down the Ctrl key,
866
- *
867
- * the link should open in the same tab. You can use handleMetaClick to achieve
868
- *
869
- * this behavior.
870
- *
871
- * @example
872
- *
873
- * const NavigationMenu = () => {
874
- * const history = useHistory();
875
- *
876
- * const handleLinkClick = (url, event) => {
877
- * // Opens url in a new tab if metaKey/CtrlKey is pressed.
878
- * // Otherwise simply redirects to url.
879
- * handleMetaClick(history, url, event);
880
- * };
881
- *
882
- * return (
883
- * <div>
884
- * <a href="/home" onClick={e => handleLinkClick("/home", e)}>
885
- * Home
886
- * </a>
887
- * <a href="/dashboard" onClick={e => handleLinkClick("/dashboard", e)}>
888
- * Dashboard
889
- * </a>
890
- * <a href="/profile" onClick={e => handleLinkClick("/profile", e)}>
891
- * Profile
892
- * </a>
893
- * </div>
894
- * );
895
- * };
896
- * @endexample
897
- */
898
- export function handleMetaClick(history: History, params: string | object, event: React.MouseEvent<HTMLElement, MouseEvent>): (options?: handleMetaClickOptions) => void;
899
- /**
900
- *
901
- * The handleMetaClick function can be used to handle onClick actions that
902
- *
903
- * redirects to a URL. It opens up the URL in a new tab if ctrl/cmd + click event
904
- *
905
- * is received. Otherwise, simply redirects to the provided URL in the same tab.
906
- *
907
- * URL can be passed as string or a history location object can be passed instead.
908
- *
909
- * Let's say you have a navigation menu with several links, and you want to allow
910
- *
911
- * users to open these links in a new tab if they hold down the Ctrl (or Cmd on
912
- *
913
- * macOS) key while clicking, and if they click without holding down the Ctrl key,
914
- *
915
- * the link should open in the same tab. You can use handleMetaClick to achieve
916
- *
917
- * this behavior.
918
- *
919
- * @example
920
- *
921
- * const NavigationMenu = () => {
922
- * const history = useHistory();
923
- *
924
- * const handleLinkClick = (url, event) => {
925
- * // Opens url in a new tab if metaKey/CtrlKey is pressed.
926
- * // Otherwise simply redirects to url.
927
- * handleMetaClick(history, url, event);
928
- * };
929
- *
930
- * return (
931
- * <div>
932
- * <a href="/home" onClick={e => handleLinkClick("/home", e)}>
933
- * Home
934
- * </a>
935
- * <a href="/dashboard" onClick={e => handleLinkClick("/dashboard", e)}>
936
- * Dashboard
937
- * </a>
938
- * <a href="/profile" onClick={e => handleLinkClick("/profile", e)}>
939
- * Profile
940
- * </a>
941
- * </div>
942
- * );
943
- * };
944
- * @endexample
945
- */
946
- export function handleMetaClick(history: History, params: string | object): (event: React.MouseEvent<HTMLElement, MouseEvent>, options?: handleMetaClickOptions) => void;
947
- /**
948
- *
949
- * The handleMetaClick function can be used to handle onClick actions that
950
- *
951
- * redirects to a URL. It opens up the URL in a new tab if ctrl/cmd + click event
952
- *
953
- * is received. Otherwise, simply redirects to the provided URL in the same tab.
954
- *
955
- * URL can be passed as string or a history location object can be passed instead.
956
- *
957
- * Let's say you have a navigation menu with several links, and you want to allow
958
- *
959
- * users to open these links in a new tab if they hold down the Ctrl (or Cmd on
960
- *
961
- * macOS) key while clicking, and if they click without holding down the Ctrl key,
962
- *
963
- * the link should open in the same tab. You can use handleMetaClick to achieve
964
- *
965
- * this behavior.
966
- *
967
- * @example
968
- *
969
- * const NavigationMenu = () => {
970
- * const history = useHistory();
971
- *
972
- * const handleLinkClick = (url, event) => {
973
- * // Opens url in a new tab if metaKey/CtrlKey is pressed.
974
- * // Otherwise simply redirects to url.
975
- * handleMetaClick(history, url, event);
976
- * };
977
- *
978
- * return (
979
- * <div>
980
- * <a href="/home" onClick={e => handleLinkClick("/home", e)}>
981
- * Home
982
- * </a>
983
- * <a href="/dashboard" onClick={e => handleLinkClick("/dashboard", e)}>
984
- * Dashboard
985
- * </a>
986
- * <a href="/profile" onClick={e => handleLinkClick("/profile", e)}>
987
- * Profile
988
- * </a>
989
- * </div>
990
- * );
991
- * };
992
- * @endexample
993
- */
994
- export function handleMetaClick(history: History): (params: string | object, event: React.MouseEvent<HTMLElement, MouseEvent>, options?: handleMetaClickOptions) => void;
995
- /**
996
- *
997
- * The isMetaKeyPressed function can be used to check whether an onClick event
998
- *
999
- * has metaKey or ctrlKey pressed.
1000
- *
1001
- * @example
1002
- *
1003
- * isMetaKeyPressed(event);
1004
- * @endexample
1005
- */
1006
- export function isMetaKeyPressed(event: React.MouseEvent<HTMLElement, MouseEvent>): boolean;
1007
- /**
1008
- *
1009
- * The useStateWithDependency hook is a utility that returns a state variable and
1010
- *
1011
- * a setter function similar to the useState hook. However, it provides
1012
- *
1013
- * additional functionality: the state variable automatically updates its value to
1014
- *
1015
- * the specified defaultValue whenever defaultValue changes. Optionally, you
1016
- *
1017
- * can also specify a dependencies array to listen for changes in other variables,
1018
- *
1019
- * which will trigger the update of the state variable.
1020
- *
1021
- * This hook will return an array with exactly two values just like useState
1022
- *
1023
- * hook.
1024
- *
1025
- * If dependencies is passed, the hook returns a state variable whose value will
1026
- *
1027
- * be updated to defaultValue in a useEffect that depends on the dependencies
1028
- *
1029
- * array. Otherwise, the useEffect will depend only on the defaultValue.
1030
- *
1031
- * @example
1032
- *
1033
- * import { useStateWithDependency } from "@bigbinary/neeto-commons-frontend/react-utils";
1034
- *
1035
- * // reset state to `defaultValue` whenever `defaultValue` changes.
1036
- * const [value, setValue] = useStateWithDependency(defaultValue);
1037
- *
1038
- * // reset state to `defaultValue` only when `value1` or `value2` changes.
1039
- * const [value, setValue] = useStateWithDependency(defaultValue, [
1040
- * value1,
1041
- * value2,
1042
- * ]);
1043
- *
1044
- * // In a case, where the value needs to be reset when defaultValue
1045
- * // changes too, defaultValue can be passed with the dependencies,
1046
- * // as shown below.
1047
- * const [value, setValue] = useStateWithDependency(defaultValue, [
1048
- * value1,
1049
- * value2,
1050
- * defaultValue,
1051
- * ]);
1052
- * @endexample
1053
- * The following code snippet demonstrates the usage of useStateWithDependency in
1054
- *
1055
- * ensuring that inputValue stays in sync with the value prop in the Rename
1056
- *
1057
- * component.
1058
- *
1059
- * @example
1060
- *
1061
- * const Rename = ({ value }) => {
1062
- * // Use the useStateWithDependency hook to manage the input value
1063
- * const [inputValue, setInputValue] = useStateWithDependency(value);
1064
- *
1065
- * // Define a handler to update the input value
1066
- * const handleInputChange = event => {
1067
- * setInputValue(event.target.value);
1068
- * };
1069
- *
1070
- * return (
1071
- * <div>
1072
- * <input type="text" value={inputValue} onChange={handleInputChange} />
1073
- * { Rest of the component }
1074
- * </div>
1075
- * );
1076
- * };
1077
- * @endexample
1078
- * As the user interacts with the input field, the inputValue state is updated to
1079
- *
1080
- * reflect the user's input. In a scenario where the value prop changes from
1081
- *
1082
- * outside the Rename component, it triggers a re-render of the Rename
1083
- *
1084
- * component. When this re-render occurs, the inputValue state is automatically
1085
- *
1086
- * updated to match the new value prop.
1087
- *
1088
- */
1089
- export function useStateWithDependency<T>(defaultValue: T, dependencies?: any[]): T;
1090
- /**
1091
- *
1092
- * The useRegisterNavigationCheckpoint hook is a utility for storing navigation
1093
- *
1094
- * checkpoints in a Zustand store. A navigation checkpoint consists of a key that
1095
- *
1096
- * identifies the checkpoint and a corresponding path to be stored in the Zustand
1097
- *
1098
- * store under that key. These registered checkpoints can be later retrieved using
1099
- *
1100
- * the useNavigationCheckpoints hook.
1101
- *
1102
- * In web applications, scenarios frequently arise where it's essential to maintain
1103
- *
1104
- * user preferences and specific application states as users navigate back and
1105
- *
1106
- * forth between different routes.
1107
- *
1108
- * A simple button, that hard codes the route as <Link to="/resource" />, won't
1109
- *
1110
- * suffice in such scenarios to navigate between pages since it won't retain any
1111
- *
1112
- * filter, search, or pagination information.
1113
- *
1114
- * This is why we have checkpoints. When a page component is mounted, a checkpoint
1115
- *
1116
- * is registered to capture the current state of the page, including the URL with
1117
- *
1118
- * applied filters, search parameters, and pagination information. If the URL
1119
- *
1120
- * changes due to user interactions, the checkpoint is automatically updated.
1121
- *
1122
- * When a user presses the back button, the value stored in the checkpoint is used
1123
- *
1124
- * as the URL. This ensures that users return to the listing page with all their
1125
- *
1126
- * previous context intact, providing a seamless and user-friendly experience.
1127
- *
1128
- * Following code snippet illustrates the usage of
1129
- *
1130
- * useRegisterNavigationCheckpoint in retaining user preference and context.
1131
- *
1132
- * @example
1133
- *
1134
- * // Import the useRegisterNavigationCheckpoint hook
1135
- * import { useRegisterNavigationCheckpoint } from "@bigbinary/neeto-commons-frontend/react-utils";
1136
- * // ...
1137
- *
1138
- * // Register a navigation checkpoint with a key and path
1139
- * useRegisterNavigationCheckpoint(
1140
- * NAVIGATION_CHECKPOINT_KEYS.ARTICLES,
1141
- * window.location.pathname + window.location.search
1142
- * );
1143
- * @endexample
1144
- * When users visit the articles page, apply specific filters, and navigate away,
1145
- *
1146
- * the navigation checkpoint captures the current URL path along with the query
1147
- *
1148
- * parameters associated with the applied filters. Later, when users return to the
1149
- *
1150
- * page, the useNavigationCheckpoints hook can retrieve the saved checkpoint
1151
- *
1152
- * using the NAVIGATION_CHECKPOINT_KEYS.ARTICLES key. This retrieved data
1153
- *
1154
- * includes the applied filters, which can then be displayed on the articles page.
1155
- *
1156
- * It is worth noting that, at BigBinary, we define the object
1157
- *
1158
- * NAVIGATION_CHECKPOINT_KEYS to store the check point keys like so:
1159
- *
1160
- * @example
1161
- *
1162
- * export const NAVIGATION_CHECKPOINT_KEYS = {
1163
- * HOME: "home",
1164
- * ARTICLES: "articles",
1165
- * };
1166
- * @endexample
1167
- */
1168
- export function useRegisterNavigationCheckpoint(key: string, path?: string, persistInLocalStorage?: boolean): void;
1169
- /**
1170
- *
1171
- * The useNavigationCheckpoints hook is a convenient tool for fetching designated
1172
- *
1173
- * navigation checkpoints stored in a Zustand store.
1174
- *
1175
- * In web applications, users frequently move between various pages or routes, and
1176
- *
1177
- * useRegisterNavigationCheckpoint empowers us to store particular paths or
1178
- *
1179
- * states as checkpoints. By employing the useNavigationCheckpoints hook, you can
1180
- *
1181
- * access these checkpoints by specifying their associated keys.
1182
- *
1183
- * We recommend reviewing the documentation for the
1184
- *
1185
- * useRegisterNavigationCheckpoint hook to
1186
- *
1187
- * gain a deeper understanding of the checkpoint concept.
1188
- *
1189
- * The following code snippet demonstrates the usage of useNavigationCheckpoints
1190
- *
1191
- * in retrieving navigation links that reflect the application's state and history.
1192
- *
1193
- * @example
1194
- *
1195
- * // Import the useNavigationCheckpoints hook
1196
- * import { useNavigationCheckpoints } from "@bigbinary/neeto-commons-frontend/react-utils";
1197
- *
1198
- * const navigationCheckpoints = useNavigationCheckpoints("home");
1199
- *
1200
- * return (
1201
- * <>
1202
- * <Link to={navigationCheckpoints["home"]}>Home</Link>
1203
- * </>
1204
- * );
1205
- * @endexample
1206
- * The above code fetches navigation checkpoint data for the home key using the
1207
- *
1208
- * useNavigationCheckpoints hook and then renders a link labeled "Home" that,
1209
- *
1210
- * when clicked, will navigate the user to the URL associated with the home
1211
- *
1212
- * navigation checkpoint.
1213
- *
1214
- */
127
+ isHistoryReplace?: boolean
128
+ }
129
+ export function handleMetaClick(
130
+ history: History,
131
+ params: string | object,
132
+ event: React.MouseEvent<HTMLElement, MouseEvent>,
133
+ options?: handleMetaClickOptions
134
+ ): void;
135
+ export function handleMetaClick(
136
+ history: History,
137
+ params: string | object,
138
+ event: React.MouseEvent<HTMLElement, MouseEvent>,
139
+ ): (options?: handleMetaClickOptions) => void;
140
+ export function handleMetaClick(
141
+ history: History,
142
+ params: string | object
143
+ ): (
144
+ event: React.MouseEvent<HTMLElement, MouseEvent>,
145
+ options?: handleMetaClickOptions
146
+ ) => void;
147
+ export function handleMetaClick(
148
+ history: History
149
+ ): (
150
+ params: string | object,
151
+ event: React.MouseEvent<HTMLElement, MouseEvent>,
152
+ options?: handleMetaClickOptions
153
+ ) => void;
154
+
155
+ export function isMetaKeyPressed(
156
+ event: React.MouseEvent<HTMLElement, MouseEvent>
157
+ ): boolean;
158
+
159
+ export function useStateWithDependency<T>(
160
+ defaultValue: T,
161
+ dependencies?: any[]
162
+ ): T;
163
+
164
+ export function useRegisterNavigationCheckpoint(
165
+ key: string,
166
+ path?: string,
167
+ persistInLocalStorage?: boolean
168
+ ): void;
169
+
1215
170
  export function useNavigationCheckpoints(...keys: string[]): {
1216
171
  [key: string]: string;
1217
172
  };
1218
- /**
1219
- *
1220
- * The useRemoveNavigationCheckpoint hook is a utility for removing a navigation
1221
- *
1222
- * checkpoint from the navigation checkpoints stored in the Zustand store.
1223
- *
1224
- * In web applications, users frequently move between various pages or routes, and
1225
- *
1226
- * useRegisterNavigationCheckpoint empowers us to store particular paths or
1227
- *
1228
- * states as checkpoints. By employing the useNavigationCheckpoints hook, you can
1229
- *
1230
- * access these checkpoints by specifying their associated keys. There might arise
1231
- *
1232
- * a case where you want to remove a particular checkpoint from the Zustand store,
1233
- *
1234
- * useRemoveNavigationCheckpoint can be used for this.
1235
- *
1236
- * We recommend reviewing the documentation for the
1237
- *
1238
- * useRegisterNavigationCheckpoint and useNavigationCheckpoints hooks for
1239
- *
1240
- * gaining a deeper understanding of the checkpoint concept.
1241
- *
1242
- * The following code snippet demonstrates the usage of
1243
- *
1244
- * useRemoveNavigationCheckpoint in removing a navigation checkpoint from the
1245
- *
1246
- * Zustand store.
1247
- *
1248
- * @example
1249
- *
1250
- * // Import the useRemoveNavigationCheckpoint hook
1251
- * import { useRemoveNavigationCheckpoint } from "@bigbinary/neeto-commons-frontend/react-utils";
1252
- *
1253
- * const removeCheckpoint = useRemoveNavigationCheckpoint();
1254
- *
1255
- * removeCheckpoint("home");
1256
- * @endexample
1257
- * The above code removes the navigation checkpoint corresponding to the home key
1258
- *
1259
- * using the useRemoveNavigationCheckpoint hook.
1260
- *
1261
- */
1262
- export function useRemoveNavigationCheckpoint(): (key: string) => void;
1263
- /**
1264
- *
1265
- * The useRestoreScrollPosition hook facilitates the restoration and synchronization of scroll positions for components using Zustand store.
1266
- *
1267
- * Maintaining scroll positions as users navigate between different routes or interact with dynamic content is crucial for preserving user context and enhancing usability. useRestoreScrollPosition addresses this by allowing components to save and restore scroll positions based on specified keys.
1268
- *
1269
- * Here's an example demonstrating how to use useRestoreScrollPosition to manage scroll positions within a React component:
1270
- *
1271
- * @example
1272
- *
1273
- * import React, { useRef } from "react";
1274
- * import useRestoreScrollPosition, { useRemoveScrollPosition } from "@bigbinary/neeto-commons-frontend/react-utils/useRestoreScrollPosition";
1275
- *
1276
- * const ScrollableComponent = ({ scrollKey }) => {
1277
- * const ref = useRef(null);
1278
- *
1279
- * // Hook to manage scroll position restoration
1280
- * useRestoreScrollPosition(scrollKey, ref);
1281
- *
1282
- * // Example of how to remove a saved scroll position
1283
- * const removeScrollPosition = useRemoveScrollPosition();
1284
- * const handleClearScrollPosition = () => {
1285
- * removeScrollPosition(scrollKey);
1286
- * };
1287
- *
1288
- * return (
1289
- * <div {...{ ref }}>
1290
- * { Scrollable content }
1291
- * <button onClick={handleClearScrollPosition}>Clear Scroll Position</button>
1292
- * </div>
1293
- * );
1294
- * }
1295
- *
1296
- * export default ScrollableComponent;
1297
- * @endexample
1298
- */
173
+
174
+ export function useRemoveNavigationCheckpoint():(key:string)=>void;
175
+
1299
176
  export function useRestoreScrollPosition(key: string, ref: React.RefObject<HTMLElement>): void;
1300
- /**
1301
- *
1302
- * A custom hook that provides access to set scroll positions.
1303
- *
1304
- * @example
1305
- *
1306
- * import { useSetScrollPosition } from "@bigbinary/neeto-commons-frontend/react-utils/useRestoreScrollPosition
1307
- *
1308
- * const setScrollPosition = useSetScrollPosition();
1309
- * setScrollPosition("myKey", 100);
1310
- * @endexample
1311
- */
1312
177
  export function useSetScrollPosition(): (key: string, value: number) => void;
1313
- /**
1314
- *
1315
- * A custom hook that retrieves the scroll position for a given key.
1316
- *
1317
- * @example
1318
- *
1319
- * import { useGetScrollPosition } from "@bigbinary/neeto-commons-frontend/react-utils/useRestoreScrollPosition
1320
- *
1321
- * const getScrollPosition = useGetScrollPosition();
1322
- * const position = getScrollPosition("myKey");
1323
- * @endexample
1324
- */
1325
178
  export function useGetScrollPosition(): (key: string) => number | undefined;
1326
- /**
1327
- *
1328
- * A custom hook that removes a scroll position entry for a specified key.
1329
- *
1330
- * @example
1331
- *
1332
- * import { useRemoveScrollPosition } from "@bigbinary/neeto-commons-frontend/react-utils/useRestoreScrollPosition
1333
- *
1334
- * const removeScrollPosition = useRemoveScrollPosition();
1335
- * removeScrollPosition("myKey");
1336
- * @endexample
1337
- */
1338
- export function useRemoveScrollPosition(): (key: string) => void;
1339
- /**
1340
- *
1341
- * The useFuncDebounce hook is a utility that extends the benefits of debouncing
1342
- *
1343
- * to functions.
1344
- *
1345
- * When the debounced function is called, it sets a timer to execute the original
1346
- *
1347
- * function after a specified delay. If the debounced function is called again
1348
- *
1349
- * before the timer expires, the previous timer is cleared. This effectively delays
1350
- *
1351
- * the execution of the original function until the debounced function hasn't been
1352
- *
1353
- * called for the specified delay period.
1354
- *
1355
- * The hook also provides a cancel method to manually cancel the execution of the
1356
- *
1357
- * debounced function before it triggers.
1358
- *
1359
- * The following code snippet demonstrates the usage of useFuncDebounce in the
1360
- *
1361
- * delaying the invocation of the fetch method until the user pauses typing for a
1362
- *
1363
- * specific period.
1364
- *
1365
- * @example
1366
- *
1367
- * import { useFuncDebounce } from "@bigbinary/neeto-commons-frontend/react-utils";
1368
- *
1369
- * const searchForProducts = useFuncDebounce(async key => {
1370
- * // this function will be triggered once after user stops typing for 300ms
1371
- * const products = await productsApi.fetch(key);
1372
- * // do something with the products
1373
- * }, 300);
1374
- *
1375
- * // component
1376
- * <Input onChange={e => searchForProducts(e.target.value)} />;
1377
- * <Button onClick={() => searchForProducts.cancel()}>Cancel search</Button>;
1378
- * @endexample
1379
- */
179
+ export function useRemoveScrollPosition():(key: string) => void;
180
+
1380
181
  export const useFuncDebounce: {
1381
182
  <F extends Function>(func: F, delay?: number): F;
1382
183
  cancel: () => void;
1383
184
  };
1384
- /**
1385
- *
1386
- * usePersistedQuery is an wrapper function around
1387
- *
1388
- * useQuery hook
1389
- *
1390
- * from react-query. In addition to all the functionalities offered useQuery,
1391
- *
1392
- * this hook also stores the received response in localStorage. For subsequent
1393
- *
1394
- * page loads, the hook will be serving data from localStorage until the API
1395
- *
1396
- * response is received.
1397
- *
1398
- * usePersistedQuery will use the staleTime config from options parameter (if
1399
- *
1400
- * present) to determine the expiry of the localStorage cache. The hook will not
1401
- *
1402
- * return data from localStorage if it is expired. Instead it will wait for the
1403
- *
1404
- * API response to become available.
1405
- *
1406
- * You can use isFreshLoading property from the return value of the hook to know
1407
- *
1408
- * whether the hook is waiting for the API. data won't be available (will be
1409
- *
1410
- * undefined) until isFreshLoading turns to false.
1411
- *
1412
- * It also provides a method getCache to get the cached data from localStorage
1413
- *
1414
- * by providing the queryKey.
1415
- *
1416
- * The following code snippet demonstrates the usage of usePersistedQuery in
1417
- *
1418
- * caching API responses and serving cached data while waiting for fresh data from
1419
- *
1420
- * the APIs.
1421
- *
1422
- * @example
1423
- *
1424
- * import { usePersistedQuery } from "@bigbinary/neeto-commons-frontend/react-utils";
1425
- *
1426
- * const useFetchUsers = options =>
1427
- * usePersistedQuery(QUERY_KEYS.FETCH_USERS, usersApi.fetch, options);
1428
- *
1429
- * // Now we can use useFetchUsers as:
1430
- * const { data, isLoading, isFreshLoading } = useFetchUsers();
1431
- *
1432
- * // To get the cached data from localStorage
1433
- * const cachedUsersData = usePersistedQuery.getCache(QUERY_KEYS.FETCH_USERS);
1434
- * @endexample
1435
- */
185
+
1436
186
  export const usePersistedQuery: {
1437
- <T>(queryKey: string | unknown[], fetch: () => Promise<T>, options?: UseQueryOptions): UseQueryResult<T> & {
1438
- isFreshLoading: boolean;
1439
- };
187
+ <T>(
188
+ queryKey: string | unknown[],
189
+ fetch: () => Promise<T>,
190
+ options?: UseQueryOptions
191
+ ): UseQueryResult<T> & { isFreshLoading: boolean };
1440
192
  getCache: <T>(queryKey: string | unknown[]) => T | null;
1441
193
  };
1442
- /**
1443
- *
1444
- * The useFetchNeetoApps hook calls
1445
- *
1446
- * neeto_apps_controller
1447
- *
1448
- * and fetches the response. neeto_apps_controller will return two information:
1449
- *
1450
- * This hook uses usePersistedQuery under the hood. So
1451
- *
1452
- * data will be immediately available except for the first page load. Additionally
1453
- *
1454
- * if the data is available in localStorage, it will be served from there until an
1455
- *
1456
- * explicit call to refetch is made.
1457
- *
1458
- * The following code snippet shows the usage of useFetchNeetoApps in fetching
1459
- *
1460
- * neetoApps and ownership status.
1461
- *
1462
- * @example
1463
- *
1464
- * import { useFetchNeetoApps } from "@bigbinary/neeto-commons-frontend/react-utils";
1465
- *
1466
- * const { neetoApps, isOwner } = useFetchNeetoApps();
1467
- * @endexample
1468
- */
1469
- export function useFetchNeetoApps(options?: UseQueryOptions): ReturnType<typeof usePersistedQuery<{
1470
- neetoApps: {
1471
- description: string;
1472
- name: string;
1473
- url: string;
1474
- }[];
1475
- isOwner: boolean;
1476
- }>>;
1477
- /**
1478
- *
1479
- * withT is an HOC which provides the t function from react-i18next to the
1480
- *
1481
- * wrapped component as a prop. withT HOC should only be used in dumb components
1482
- *
1483
- * i.e, components which have no logic other than rendering something and the
1484
- *
1485
- * useTranslation hook.
1486
- *
1487
- * @example
1488
- *
1489
- * // Example usage of withT:
1490
- * const ComponentWithTranslation = withT(({ t }) => <div>{t("some.key")}</div>);
1491
- *
1492
- * // Example usage of withT with forwarded ref:
1493
- * const ComponentWithRef = withT(
1494
- * React.forwardRef(({ t }, ref) => <div ref={ref}>{t("some.key")}</div>),
1495
- * {
1496
- * withRef: true,
1497
- * }
1498
- * );
1499
- *
1500
- * // Example usage of withT with keyPrefix:
1501
- * const ComponentWithTranslation = withT(
1502
- * ({ t }) => (
1503
- * // t function will be called with the key "very.nested.key.some.key"
1504
- * <div ref={ref}>{t("some.key")}</div>
1505
- * ),
1506
- * {
1507
- * keyPrefix: "very.nested.key",
1508
- * }
1509
- * );
1510
- * @endexample
1511
- */
1512
- export const withT: <Props extends {
1513
- [key: string]: any;
1514
- }, N extends Namespace = DefaultNamespace, TKPrefix extends KeyPrefix<N> = undefined>(Component: React.ComponentType<Props & {
1515
- t: TFunction;
1516
- }>, options?: {
1517
- withRef?: boolean;
1518
- keyPrefix?: TKPrefix;
1519
- }, ns?: N) => React.ComponentType<Props>;
194
+
195
+ export function useFetchNeetoApps(
196
+ options?: UseQueryOptions
197
+ ): ReturnType<
198
+ typeof usePersistedQuery<{
199
+ neetoApps: { description: string; name: string; url: string }[];
200
+ isOwner: boolean;
201
+ }>
202
+ >;
203
+
204
+ export const withT: <
205
+ Props extends { [key: string]: any },
206
+ N extends Namespace = DefaultNamespace,
207
+ TKPrefix extends KeyPrefix<N> = undefined
208
+ >(
209
+ Component: React.ComponentType<Props & { t: TFunction }>,
210
+ options?: {
211
+ withRef?: boolean;
212
+ keyPrefix?: TKPrefix;
213
+ },
214
+ ns?: N
215
+ ) => React.ComponentType<Props>;
216
+
1520
217
  type QueryKeyOrFilters = QueryKey | QueryFilters;
1521
- /**
1522
- *
1523
- * useMutationWithInvalidation is a wrapper function around the
1524
- *
1525
- * useMutation
1526
- *
1527
- * hook from react-query. It returns all the props from the useMutation hook and
1528
- *
1529
- * additionally, invalidates a list of query keys on mutation success.
1530
- *
1531
- * The following code snippet illustrates the usage of
1532
- *
1533
- * useMutationWithInvalidation across various scenarios.
1534
- *
1535
- * @example
1536
- *
1537
- * // useQuestionsApi
1538
- * //Invalidate any query with query key starting with "QUESTIONS"
1539
- * const useUpdateQuestions = () =>
1540
- * useMutationWithInvalidation(questionsApi.update, {
1541
- * keysToInvalidate: ["QUESTIONS"],
1542
- * onSuccess: data => queryClient.setQueryData(["RESPONSES"], data),
1543
- * });
1544
- *
1545
- * // The above is the same as writing
1546
- * const useUpdateQuestions = options =>
1547
- * useMutation(questionsApi.update, {
1548
- * ...options,
1549
- * onSuccess: (data, ...args) => {
1550
- * queryClient.invalidateQueries({
1551
- * queryKey: ["QUESTIONS"]
1552
- * });
1553
- * queryClient.setQueryData(["RESPONSES"], data);
1554
- * options?.onSuccess(data, ...args);
1555
- * },
1556
- * });
1557
- * @endexample
1558
- * @example
1559
- *
1560
- * //Invalidate any query with query key starting with ["FORM", "QUESTIONS"]
1561
- * const useUpdateQuestions = options =>
1562
- * useMutationWithInvalidation(questionsApi.update, {
1563
- * keysToInvalidate: [["FORM", "QUESTIONS"]],
1564
- * ...options,
1565
- * });
1566
- *
1567
- * // The above is the same as writing
1568
- * const useUpdateQuestions = options =>
1569
- * useMutation(questionsApi.update, {
1570
- * ...options,
1571
- * onSuccess: (...args) => {
1572
- * queryClient.invalidateQueries({
1573
- * queryKey: ["FORM", "QUESTIONS"],
1574
- * });
1575
- * options?.onSuccess(...args);
1576
- * },
1577
- * });
1578
- * @endexample
1579
- * @example
1580
- *
1581
- * //Invalidate any query with query key starting with "FORM" or starting with "QUESTIONS"
1582
- * const useUpdateQuestions = options =>
1583
- * useMutationWithInvalidation(questionsApi.update, {
1584
- * keysToInvalidate: ["FORM", "QUESTIONS"],
1585
- * ...options,
1586
- * });
1587
- *
1588
- * // The above is the same as writing
1589
- * const useUpdateQuestions = options =>
1590
- * useMutation(questionsApi.update, {
1591
- * ...options,
1592
- * onSuccess: () => {
1593
- * queryClient.invalidateQueries({
1594
- * queryKey: ["FORM"],
1595
- * });
1596
- * queryClient.invalidateQueries({
1597
- * queryKey: ["QUESTIONS"],
1598
- * });
1599
- * options?.onSuccess(...args);
1600
- * },
1601
- * });
1602
- * @endexample
1603
- * @example
1604
- *
1605
- * //Invalidate any query with query key starting with ["QUESTION", id]
1606
- * const useUpdateQuestions = options =>
1607
- * useMutationWithInvalidation(questionsApi.update, {
1608
- * keysToInvalidate: [(_, { id }) => ["QUESTION", id]],
1609
- * ...options,
1610
- * });
1611
- *
1612
- * // The above is the same as writing
1613
- * const useUpdateQuestions = options =>
1614
- * useMutation(questionsApi.update, {
1615
- * ...options,
1616
- * onSuccess: (...args) => {
1617
- * const [_, { id }] = args;
1618
- * queryClient.invalidateQueries({
1619
- * queryKey: ["QUESTION", id],
1620
- * });
1621
- * options?.onSuccess(...args);
1622
- * },
1623
- * });
1624
- *
1625
- * // Update question component
1626
- * const { mutate: updateQuestions, isPending } = useUpdateQuestions({
1627
- * onError: e => logger.error(e),
1628
- * });
1629
- * @endexample
1630
- */
1631
- export function useMutationWithInvalidation<TData = unknown, TError = unknown, TVariables = void, TContext = unknown>(mutationFn: MutationFunction<TData, TVariables>, options: {
1632
- keysToInvalidate: Array<QueryKeyOrFilters | ((data: TData, variables: TVariables, context: TContext | undefined) => QueryKeyOrFilters)>;
1633
- } & Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn'>): UseMutationResult<TData, TError, TVariables, TContext>;
1634
- /**
1635
- *
1636
- * The useQueryParams hook can be used to retrieve the query parameters whenever
1637
- *
1638
- * the location changes. A change in location will trigger rerender when using this
1639
- *
1640
- * hook.
1641
- *
1642
- * This hook will return an object containing all the query parameters in camel
1643
- *
1644
- * case. It will return an empty object if no query parameters are present.
1645
- *
1646
- * You can set toCamelCase to false if you don't want to apply any transformation to the keys.
1647
- *
1648
- * More details on working:
1649
- *
1650
- * https://www.loom.com/share/4f369cff56e845428d5ef7451759469c
1651
- *
1652
- * @example
1653
- *
1654
- * const queryParams = useQueryParams();
1655
- * // output: { sort_by: "description", order_by: "desc" }
1656
- * const { sortBy, orderBy } = useQueryParams();
1657
- *
1658
- * const { sort_by, order_by } = useQueryParams({ toCamelCase: false });
1659
- * @endexample
1660
- */
218
+
219
+ export function useMutationWithInvalidation<TData = unknown, TError = unknown, TVariables = void, TContext = unknown>(
220
+ mutationFn: MutationFunction<TData, TVariables>,
221
+ options: { keysToInvalidate: Array<QueryKeyOrFilters | ((data: TData, variables: TVariables, context: TContext | undefined) => QueryKeyOrFilters)> } & Omit<UseMutationOptions<TData, TError, TVariables, TContext>, 'mutationFn'>
222
+ ): UseMutationResult<TData, TError, TVariables, TContext>;
223
+
1661
224
  export function useQueryParams(options?: qsOptionsType): QueryParamsType;
225
+
1662
226
  type BreakpointKeys = 'mobile' | 'tablet' | 'desktop' | 'largeDesktop';
1663
- type Breakpoints = { [key in BreakpointKeys]: boolean };
1664
- /**
1665
- *
1666
- * The useBreakpoints hook is a utility for responsive styling on components
1667
- *
1668
- * based on the viewport size. It returns the current breakpoint name and a
1669
- *
1670
- * function to check if the current breakpoint matches a given breakpoint name. It
1671
- *
1672
- * also re-renders the component when the current breakpoint changes.
1673
- *
1674
- * Note: Use this hook only if you need the component to re-render when the
1675
- *
1676
- * current breakpoint change happens. If all you need is plain read and write
1677
- *
1678
- * operations on the current breakpoint, prefer the vanilla window.matchMedia or
1679
- *
1680
- * window.innerWidth API.
1681
- *
1682
- * @example
1683
- *
1684
- * (window) => {
1685
- * mobile: window.innerWidth < 768,
1686
- * tablet: window.innerWidth >= 768 && window.innerWidth < 1024,
1687
- * desktop: window.innerWidth >= 1024 && window.innerWidth < 1280,
1688
- * largeDesktop: window.innerWidth >= 1280,
1689
- * }
1690
- * @endexample
1691
- * This hook will return an object with two values currentSize and isSize.
1692
- *
1693
- * The following code snippet illustrates the usage of useLocalStorage in
1694
- *
1695
- * implementing a theme-switching feature.
1696
- *
1697
- * @example
1698
- *
1699
- * import { useBreakpoints } from "@bigbinary/neeto-commons-frontend/react-utils";
1700
- *
1701
- * const { currentSize, isSize } = useBreakpoints();
1702
- *
1703
- * // When window.innerWidth is 1028
1704
- * console.log(currentSize); // logs `tablet`
1705
- * console.log(isSize("mobile")); // logs `false`
1706
- * console.log(isSize("tablet")); // logs `true`
1707
- * @endexample
1708
- * We can also override the default breakpoints by passing a function to the
1709
- *
1710
- * useBreakpoints hook.
1711
- *
1712
- * @example
1713
- *
1714
- * import { useBreakpoints } from "@bigbinary/neeto-commons-frontend/react-utils";
1715
- *
1716
- * // Overriding the default breakpoints
1717
- * const { currentSize, isSize } = useBreakpoints(window => ({
1718
- * largeDesktop: window.innerWidth >= 1280 && window.innerWidth < 1440,
1719
- * extraLargeDesktop: window.innerWidth >= 1440,
1720
- * }));
1721
- *
1722
- * // When window.innerWidth is 1440
1723
- * console.log(currentSize); // logs `extraLargeDesktop`
1724
- * console.log(isSize("extraLargeDesktop")); // logs `true`
1725
- * @endexample
1726
- */
1727
- export function useBreakpoints<T extends {}>(breakpointOverrides?: (window: Window) => Partial<T & Breakpoints>): {
1728
- currentSize: BreakpointKeys | keyof T;
1729
- isSize: (size: BreakpointKeys | keyof T) => boolean;
1730
- };
227
+
228
+ type Breakpoints = {
229
+ [key in BreakpointKeys]: boolean;
230
+ }
231
+
232
+ export function useBreakpoints<T extends {}>(breakpointOverrides?: (window: Window) => Partial<T & Breakpoints>): { currentSize: BreakpointKeys | keyof T; isSize: (size: BreakpointKeys | keyof T) => boolean };