@react-pakistan/util-functions 1.24.59 → 1.24.60

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.
@@ -1,6 +1,8 @@
1
1
  export interface FetchResult {
2
2
  data: any;
3
3
  error: any;
4
+ status?: number;
5
+ ok?: boolean;
4
6
  }
5
7
  export interface FetchConfig extends RequestInit {
6
8
  autoFetch?: boolean;
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- /* eslint-disable @typescript-eslint/no-explicit-any, no-void */
2
+ /* eslint-disable @typescript-eslint/no-explicit-any, no-void, no-restricted-globals */
3
3
  var __assign = (this && this.__assign) || function () {
4
4
  __assign = Object.assign || function(t) {
5
5
  for (var s, i = 1, n = arguments.length; i < n; i++) {
@@ -94,7 +94,7 @@ var useFetch = function (url, config, deps) {
94
94
  };
95
95
  }, []);
96
96
  var fetchNow = (0, react_1.useCallback)(function (overrideUrl, overrideOptions) { return __awaiter(void 0, void 0, void 0, function () {
97
- var finalUrl, finalOptions, controller, response, result, err_1;
97
+ var finalUrl, finalOptions, controller, response, parsed, e_1, err, err_1;
98
98
  return __generator(this, function (_a) {
99
99
  switch (_a.label) {
100
100
  case 0:
@@ -108,45 +108,73 @@ var useFetch = function (url, config, deps) {
108
108
  finalOptions.signal = controller.signal;
109
109
  _a.label = 1;
110
110
  case 1:
111
- _a.trys.push([1, 4, 5, 6]);
111
+ _a.trys.push([1, 7, 8, 9]);
112
112
  return [4 /*yield*/, fetch(finalUrl, finalOptions)];
113
113
  case 2:
114
114
  response = _a.sent();
115
- if (!response.ok) {
116
- throw new Error("HTTP error! status: ".concat(response.status));
117
- }
118
- return [4 /*yield*/, response.json()];
115
+ parsed = null;
116
+ _a.label = 3;
119
117
  case 3:
120
- result = _a.sent();
118
+ _a.trys.push([3, 5, , 6]);
119
+ return [4 /*yield*/, response.json()];
120
+ case 4:
121
+ parsed = _a.sent();
122
+ return [3 /*break*/, 6];
123
+ case 5:
124
+ e_1 = _a.sent();
125
+ // non-json or empty body
126
+ parsed = null;
127
+ return [3 /*break*/, 6];
128
+ case 6:
121
129
  if (isMounted.current) {
122
- setData(result);
123
- setError(null);
124
- setApiResult(API_RESULT.SUCCESS);
125
- callback === null || callback === void 0 ? void 0 : callback({ data: result, error: null });
130
+ if (response.ok) {
131
+ setData(parsed);
132
+ setError(null);
133
+ setApiResult(API_RESULT.SUCCESS);
134
+ callback === null || callback === void 0 ? void 0 : callback({
135
+ data: parsed,
136
+ error: null,
137
+ status: response.status,
138
+ ok: true,
139
+ });
140
+ }
141
+ else {
142
+ err = new Error("HTTP error! status: ".concat(response.status));
143
+ setError(err);
144
+ setData(parsed);
145
+ setApiResult(API_RESULT.ERROR);
146
+ callback === null || callback === void 0 ? void 0 : callback({
147
+ data: parsed,
148
+ error: err,
149
+ status: response.status,
150
+ ok: false,
151
+ });
152
+ }
126
153
  }
127
- return [3 /*break*/, 6];
128
- case 4:
154
+ return [3 /*break*/, 9];
155
+ case 7:
129
156
  err_1 = _a.sent();
130
157
  if (isMounted.current) {
131
158
  setError(err_1);
132
159
  setData(null);
133
160
  setApiResult(API_RESULT.ERROR);
134
- callback === null || callback === void 0 ? void 0 : callback({ data: null, error: err_1 });
161
+ callback === null || callback === void 0 ? void 0 : callback({
162
+ data: null,
163
+ error: err_1,
164
+ status: undefined,
165
+ ok: false,
166
+ });
135
167
  }
136
- return [3 /*break*/, 6];
137
- case 5:
168
+ return [3 /*break*/, 9];
169
+ case 8:
138
170
  if (isMounted.current) {
139
171
  setLoading(false);
140
172
  }
141
173
  return [7 /*endfinally*/];
142
- case 6: return [2 /*return*/];
174
+ case 9: return [2 /*return*/];
143
175
  }
144
176
  });
145
- }); }, __spreadArray([
146
- url,
147
- defaultOptions,
148
- callback
149
- ], deps, true));
177
+ }); }, __spreadArray([url, defaultOptions, callback], deps, true));
150
178
  (0, react_1.useEffect)(function () {
151
179
  if (autoFetch) {
152
180
  fetchNow();
@@ -2,6 +2,8 @@ import { FetchConfig } from './use-fetch';
2
2
  export interface CallbackParams {
3
3
  data: any;
4
4
  error: any;
5
+ status?: number;
6
+ ok?: boolean;
5
7
  }
6
8
  interface Params {
7
9
  byIdCallback: (d: CallbackParams) => void;
@@ -29,7 +31,7 @@ interface Return {
29
31
  deleteFetchNow?: (url?: string, config?: FetchConfig) => void;
30
32
  deleteLoading: boolean;
31
33
  listError?: Error;
32
- listFetchNow: () => void;
34
+ listFetchNow: (url?: string, config?: FetchConfig) => void;
33
35
  listLoading: boolean;
34
36
  updateError?: Error;
35
37
  updateFetchNow: (url?: string, config?: FetchConfig) => void;
@@ -1,5 +1,5 @@
1
1
  "use strict";
2
- /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ /* eslint-disable @typescript-eslint/no-explicit-any, no-restricted-globals */
3
3
  var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
4
4
  if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
5
5
  if (ar || !(i in from)) {
@@ -11,23 +11,70 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
11
11
  };
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.useModuleEntity = void 0;
14
+ var react_1 = require("react");
14
15
  var constants_1 = require("../constants");
15
16
  var use_fetch_1 = require("./use-fetch");
16
17
  var use_debounce_1 = require("./use-debounce");
17
18
  var useModuleEntity = function (_a) {
18
19
  var byIdCallback = _a.byIdCallback, _b = _a.byIdDeps, byIdDeps = _b === void 0 ? [] : _b, byIdParams = _a.byIdParams, deleteCallback = _a.deleteCallback, _c = _a.deleteDeps, deleteDeps = _c === void 0 ? [] : _c, deleteParams = _a.deleteParams, listCallback = _a.listCallback, _d = _a.listDeps, listDeps = _d === void 0 ? [] : _d, listParams = _a.listParams, listUrl = _a.listUrl, searchQuery = _a.searchQuery, unitByIdUrl = _a.unitByIdUrl, unitUrl = _a.unitUrl, updateCallback = _a.updateCallback, _e = _a.updateDeps, updateDeps = _e === void 0 ? [] : _e, updateParams = _a.updateParams;
19
20
  var debouncedQuery = (0, use_debounce_1.useDebounce)(searchQuery, 800);
21
+ // debounced list refresh to batch multiple updates/deletes
22
+ var refreshTimerRef = (0, react_1.useRef)(null);
23
+ (0, react_1.useEffect)(function () { return function () {
24
+ if (refreshTimerRef.current) {
25
+ globalThis.clearTimeout(refreshTimerRef.current);
26
+ refreshTimerRef.current = null;
27
+ }
28
+ }; }, []);
20
29
  // list
21
30
  var _f = (0, use_fetch_1.useFetch)(listUrl, {
22
31
  method: constants_1.API_METHODS.POST,
23
32
  body: JSON.stringify(listParams),
24
33
  callback: listCallback,
25
- }, __spreadArray([debouncedQuery], listDeps, true)), listError = _f.error, listFetchNow = _f.fetchNow, listLoading = _f.loading;
34
+ }, __spreadArray([debouncedQuery, JSON.stringify(listParams)], listDeps, true)), listError = _f.error, listFetchNow = _f.fetchNow, listLoading = _f.loading;
35
+ var refreshList = function (delay) {
36
+ if (delay === void 0) { delay = 300; }
37
+ if (refreshTimerRef.current) {
38
+ globalThis.clearTimeout(refreshTimerRef.current);
39
+ }
40
+ refreshTimerRef.current = globalThis.setTimeout(function () {
41
+ try {
42
+ // pass current list params explicitly so the fetch uses the latest values
43
+ listFetchNow(undefined, {
44
+ method: constants_1.API_METHODS.POST,
45
+ body: JSON.stringify(listParams),
46
+ });
47
+ }
48
+ catch (e) {
49
+ // noop
50
+ }
51
+ refreshTimerRef.current = null;
52
+ }, delay);
53
+ };
26
54
  // create / edit
27
55
  var _g = (0, use_fetch_1.useFetch)(unitUrl, {
28
56
  method: constants_1.API_METHODS.POST,
29
57
  body: JSON.stringify(updateParams),
30
- callback: updateCallback,
58
+ callback: function (d) {
59
+ if (updateCallback) {
60
+ try {
61
+ updateCallback(d);
62
+ }
63
+ catch (e) {
64
+ // swallow callback errors to ensure list refresh still runs
65
+ // caller's callback is responsible for its own error handling
66
+ }
67
+ }
68
+ // refresh the list after update/create only when the operation succeeded
69
+ try {
70
+ if (d && d.ok) {
71
+ refreshList();
72
+ }
73
+ }
74
+ catch (e) {
75
+ // noop
76
+ }
77
+ },
31
78
  }, __spreadArray([], updateDeps, true)), updateError = _g.error, updateLoading = _g.loading, updateFetchNow = _g.fetchNow;
32
79
  // by id
33
80
  var _h = (0, use_fetch_1.useFetch)(unitByIdUrl, {
@@ -39,7 +86,25 @@ var useModuleEntity = function (_a) {
39
86
  var _j = (0, use_fetch_1.useFetch)(unitUrl, {
40
87
  method: constants_1.API_METHODS.DELETE,
41
88
  body: JSON.stringify(deleteParams),
42
- callback: deleteCallback,
89
+ callback: function (d) {
90
+ if (deleteCallback) {
91
+ try {
92
+ deleteCallback(d);
93
+ }
94
+ catch (e) {
95
+ // swallow callback errors to ensure list refresh still runs
96
+ }
97
+ }
98
+ // refresh the list after delete only when the operation succeeded
99
+ try {
100
+ if (d && d.ok) {
101
+ refreshList();
102
+ }
103
+ }
104
+ catch (e) {
105
+ // noop
106
+ }
107
+ },
43
108
  }, __spreadArray([], deleteDeps, true)), deleteError = _j.error, deleteLoading = _j.loading, deleteFetchNow = _j.fetchNow;
44
109
  return {
45
110
  byIdError: byIdError,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-pakistan/util-functions",
3
- "version": "1.24.59",
3
+ "version": "1.24.60",
4
4
  "description": "A library of all util functions",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -45,6 +45,8 @@
45
45
  "@babel/preset-typescript": "^7.24.1",
46
46
  "@microsoft/tsdoc": "^0.14.2",
47
47
  "@react-pakistan/eslint-config-shared": "^1.11.3",
48
+ "@testing-library/react": "^14.0.0",
49
+ "@testing-library/react-hooks": "^8.0.1",
48
50
  "@types/jest": "^29.5.12",
49
51
  "@types/lodash.curry": "^4.1.9",
50
52
  "@types/node": "^20.12.8",
@@ -59,12 +61,14 @@
59
61
  "eslint-plugin-import": "^2.29.1",
60
62
  "husky": "^9.0.11",
61
63
  "jest": "^29.7.0",
64
+ "jest-environment-jsdom": "^29.7.0",
62
65
  "libphonenumber-js": "^1.12.13",
63
66
  "lint-staged": "^15.2.2",
64
67
  "lodash.curry": "^4.1.1",
65
68
  "lodash.isequal": "^4.5.0",
66
69
  "next": "^15",
67
- "react": "^19",
70
+ "react": "^19.2.0",
71
+ "react-dom": "^19.2.0",
68
72
  "react-use": "^17",
69
73
  "rimraf": "^5.0.5",
70
74
  "ts-jest": "^29",
@@ -0,0 +1 @@
1
+ export declare function __restoreConsoleErrors(): void;
package/setupTests.js ADDED
@@ -0,0 +1,53 @@
1
+ "use strict";
2
+ // Jest setup file: selectively filter noisy console.error messages that are
3
+ // expected under the test environment. We keep other console.error messages
4
+ // intact so real failures still surface.
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.__restoreConsoleErrors = __restoreConsoleErrors;
7
+ var origConsoleError = console.error;
8
+ var IGNORED_PATTERNS = [
9
+ // React (production build) act warning that appears from some imported
10
+ // production builds of React when using the test renderer.
11
+ /act\(\.\.\.\) is not supported in production builds of React/,
12
+ // ReactDOM warning when the test environment isn't configured for concurrent act
13
+ /The current testing environment is not configured to support act\(\.\.\.\)/,
14
+ // requestAnimationFrame / cancelAnimationFrame polyfill warnings from
15
+ // some vendor bundles that check for window.requestAnimationFrame
16
+ /This browser doesn't support requestAnimationFrame/,
17
+ /This browser doesn't support cancelAnimationFrame/,
18
+ // forceFrameRate debug warning from some React builds
19
+ /forceFrameRate takes a positive int between 0 and 125/,
20
+ // Deprecation message when code (or a dependency) calls act from
21
+ // react-dom/test-utils instead of React.act
22
+ /ReactDOMTestUtils\.act.*is deprecated in favor of .*React\.act/,
23
+ ];
24
+ console.error = function () {
25
+ var _a;
26
+ var args = [];
27
+ for (var _i = 0; _i < arguments.length; _i++) {
28
+ args[_i] = arguments[_i];
29
+ }
30
+ try {
31
+ if (args.length > 0) {
32
+ var first = String((_a = args[0]) !== null && _a !== void 0 ? _a : '');
33
+ for (var _b = 0, IGNORED_PATTERNS_1 = IGNORED_PATTERNS; _b < IGNORED_PATTERNS_1.length; _b++) {
34
+ var rx = IGNORED_PATTERNS_1[_b];
35
+ if (rx.test(first)) {
36
+ // swallow this noisy, expected message
37
+ return;
38
+ }
39
+ }
40
+ }
41
+ }
42
+ catch (e) {
43
+ // if anything goes wrong while matching, fall back to original
44
+ return origConsoleError.apply(void 0, args);
45
+ }
46
+ // otherwise call original
47
+ return origConsoleError.apply(void 0, args);
48
+ };
49
+ // Provide a small helper to restore console in case tests need it
50
+ function __restoreConsoleErrors() {
51
+ // @ts-ignore
52
+ console.error = origConsoleError;
53
+ }