loading_bar.ts 2.3 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485
  1. import {
  2. isAsyncThunkAction,
  3. isPending as isThunkActionPending,
  4. isFulfilled as isThunkActionFulfilled,
  5. isRejected as isThunkActionRejected,
  6. isAction,
  7. } from '@reduxjs/toolkit';
  8. import type { Middleware, UnknownAction } from '@reduxjs/toolkit';
  9. import { showLoading, hideLoading } from 'react-redux-loading-bar';
  10. import type { RootState } from '..';
  11. interface Config {
  12. promiseTypeSuffixes?: string[];
  13. }
  14. const defaultTypeSuffixes: Config['promiseTypeSuffixes'] = [
  15. 'PENDING',
  16. 'FULFILLED',
  17. 'REJECTED',
  18. ];
  19. interface ActionWithSkipLoading extends UnknownAction {
  20. skipLoading: boolean;
  21. }
  22. function isActionWithSkipLoading(
  23. action: unknown,
  24. ): action is ActionWithSkipLoading {
  25. return (
  26. isAction(action) &&
  27. 'skipLoading' in action &&
  28. typeof action.skipLoading === 'boolean'
  29. );
  30. }
  31. export const loadingBarMiddleware = (
  32. config: Config = {},
  33. ): Middleware<{ skipLoading?: boolean }, RootState> => {
  34. const promiseTypeSuffixes = config.promiseTypeSuffixes ?? defaultTypeSuffixes;
  35. return ({ dispatch }) =>
  36. (next) =>
  37. (action) => {
  38. let isPending = false;
  39. let isFulfilled = false;
  40. let isRejected = false;
  41. if (
  42. isAsyncThunkAction(action)
  43. // TODO: once we get the first use-case for it, add a check for skipLoading
  44. ) {
  45. if (isThunkActionPending(action)) isPending = true;
  46. else if (isThunkActionFulfilled(action)) isFulfilled = true;
  47. else if (isThunkActionRejected(action)) isRejected = true;
  48. } else if (
  49. isActionWithSkipLoading(action) &&
  50. !action.skipLoading &&
  51. typeof action.type === 'string'
  52. ) {
  53. const [PENDING, FULFILLED, REJECTED] = promiseTypeSuffixes;
  54. const isPendingRegexp = new RegExp(`${PENDING}$`, 'g');
  55. const isFulfilledRegexp = new RegExp(`${FULFILLED}$`, 'g');
  56. const isRejectedRegexp = new RegExp(`${REJECTED}$`, 'g');
  57. if (action.type.match(isPendingRegexp)) {
  58. isPending = true;
  59. } else if (action.type.match(isFulfilledRegexp)) {
  60. isFulfilled = true;
  61. } else if (action.type.match(isRejectedRegexp)) {
  62. isRejected = true;
  63. }
  64. }
  65. if (isPending) {
  66. dispatch(showLoading());
  67. } else if (isFulfilled || isRejected) {
  68. dispatch(hideLoading());
  69. }
  70. return next(action);
  71. };
  72. };