@credithub/harlan-components 1.128.0 → 1.130.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.
@@ -3,6 +3,7 @@ import { Client } from '@credithub/webservice';
3
3
  import React, { createContext, useCallback, useContext, useEffect, useMemo, useState } from 'react';
4
4
  import Section from './section';
5
5
  import { RequestStatus } from './requestContextTypes';
6
+ import { classifyRequestError, isErrorWithPushFlag } from '../utils/classifyRequestError';
6
7
  export * from './requestContextTypes';
7
8
  export var WebService = createContext(new Client.WebService());
8
9
  export var RequestDefaultsContext = createContext({});
@@ -77,12 +78,20 @@ var extractExceptionFromDocument = function (document) {
77
78
  }
78
79
  return null;
79
80
  };
80
- var isErrorWithPush = function (error) {
81
- if (error && typeof error === 'object') {
82
- return (error === null || error === void 0 ? void 0 : error.push) === true;
83
- }
84
- return false;
85
- };
81
+ function pushNoticeFromError(requestError) {
82
+ var _a;
83
+ var err = requestError;
84
+ var trimmed = (_a = err === null || err === void 0 ? void 0 : err.message) === null || _a === void 0 ? void 0 : _a.trim();
85
+ var code = typeof (err === null || err === void 0 ? void 0 : err.code) === 'number' && !Number.isNaN(err.code)
86
+ ? err.code
87
+ : undefined;
88
+ var notice = {};
89
+ if (trimmed)
90
+ notice.message = trimmed;
91
+ if (code != null)
92
+ notice.code = code;
93
+ return notice;
94
+ }
86
95
  export function CustomProvider(Provider, query) {
87
96
  return function (_a) {
88
97
  var children = _a.children, data = _a.data, urlData = _a.urlData, _b = _a.depends, depends = _b === void 0 ? [] : _b;
@@ -96,6 +105,7 @@ export function CustomProvider(Provider, query) {
96
105
  var _j = useState(false), showLoadingBar = _j[0], setShowLoadingBar = _j[1];
97
106
  var _k = useState(false), shouldRetry = _k[0], setShouldRetry = _k[1];
98
107
  var _l = useState(false), requestCompleted = _l[0], setRequestCompleted = _l[1];
108
+ var _m = useState(null), pushNotice = _m[0], setPushNotice = _m[1];
99
109
  var dependentRequestsCompleted = useMemo(function () {
100
110
  return depends === null || depends === void 0 ? void 0 : depends.every(function (request) {
101
111
  return (request === null || request === void 0 ? void 0 : request.type) === RequestStatus.Success ||
@@ -121,6 +131,7 @@ export function CustomProvider(Provider, query) {
121
131
  return;
122
132
  setLoading(true);
123
133
  setError(null);
134
+ setPushNotice(null);
124
135
  setShowLoadingBar(true);
125
136
  simulateProgress();
126
137
  var requestId = Date.now();
@@ -137,17 +148,18 @@ export function CustomProvider(Provider, query) {
137
148
  .then(function (parsedResponse) {
138
149
  setResponse(parsedResponse);
139
150
  setError(null);
151
+ setPushNotice(null);
140
152
  setRequestCompleted(true);
141
153
  })
142
154
  .catch(function (requestError) {
143
- if (requestError.name !== 'AbortError') {
144
- // Se o erro tem push === true, não tratar como erro (caso esperado)
145
- if (isErrorWithPush(requestError)) {
146
- // Tratar como sucesso (sem erro)
155
+ if (classifyRequestError(requestError) !== 'aborted') {
156
+ if (isErrorWithPushFlag(requestError)) {
147
157
  setError(null);
158
+ setPushNotice(pushNoticeFromError(requestError));
148
159
  setRequestCompleted(true);
149
160
  }
150
161
  else {
162
+ setPushNotice(null);
151
163
  setError(requestError instanceof Error
152
164
  ? requestError
153
165
  : new Error(String(requestError)));
@@ -193,7 +205,8 @@ export function CustomProvider(Provider, query) {
193
205
  !loading &&
194
206
  requestsMap.size === 0 &&
195
207
  !requestCompleted &&
196
- dependentRequestsCompleted) {
208
+ dependentRequestsCompleted &&
209
+ !shouldRetry) {
197
210
  fetchData();
198
211
  }
199
212
  }, [
@@ -202,7 +215,8 @@ export function CustomProvider(Provider, query) {
202
215
  loading,
203
216
  requestsMap,
204
217
  requestCompleted,
205
- dependentRequestsCompleted
218
+ dependentRequestsCompleted,
219
+ shouldRetry
206
220
  ]);
207
221
  useEffect(function () {
208
222
  if (shouldRetry) {
@@ -214,6 +228,10 @@ export function CustomProvider(Provider, query) {
214
228
  var contextValue = useMemo(function () {
215
229
  var activeRequestsCount = requestsMap.size;
216
230
  var warningMessage = extractWarningFromDocument(response === null || response === void 0 ? void 0 : response.document);
231
+ var terminalPushSuccess = requestCompleted &&
232
+ !error &&
233
+ !response &&
234
+ pushNotice != null;
217
235
  return {
218
236
  type: error
219
237
  ? RequestStatus.Error
@@ -221,7 +239,9 @@ export function CustomProvider(Provider, query) {
221
239
  ? RequestStatus.Success
222
240
  : loading
223
241
  ? RequestStatus.Loading
224
- : RequestStatus.Empty,
242
+ : terminalPushSuccess
243
+ ? RequestStatus.Success
244
+ : RequestStatus.Empty,
225
245
  error: error,
226
246
  data: mergedData,
227
247
  urlData: mergedUrlData,
@@ -235,7 +255,8 @@ export function CustomProvider(Provider, query) {
235
255
  progress: progress,
236
256
  activeRequests: activeRequestsCount,
237
257
  showLoadingBar: showLoadingBar,
238
- warningMessage: warningMessage
258
+ warningMessage: warningMessage,
259
+ pushNotice: pushNotice
239
260
  };
240
261
  }, [
241
262
  error,
@@ -245,7 +266,9 @@ export function CustomProvider(Provider, query) {
245
266
  loading,
246
267
  progress,
247
268
  requestsMap,
248
- showLoadingBar
269
+ showLoadingBar,
270
+ pushNotice,
271
+ requestCompleted
249
272
  ]);
250
273
  return (React.createElement(Provider.Provider, { value: contextValue }, children));
251
274
  };
@@ -256,9 +279,10 @@ export function useQuery(query, data, enabled) {
256
279
  var _a = useContext(RequestDefaultsContext), defaultData = _a.data, defaultUrlData = _a.urlData;
257
280
  var _b = useState(null), response = _b[0], setResponse = _b[1];
258
281
  var _c = useState(null), error = _c[0], setError = _c[1];
259
- var _d = useState(false), isLoading = _d[0], setIsLoading = _d[1];
260
- var _e = useState(true), shouldFetch = _e[0], setShouldFetch = _e[1];
261
- var _f = useState(0), loadingProgress = _f[0], setProgress = _f[1];
282
+ var _d = useState(null), pushNotice = _d[0], setPushNotice = _d[1];
283
+ var _e = useState(false), isLoading = _e[0], setIsLoading = _e[1];
284
+ var _f = useState(true), shouldFetch = _f[0], setShouldFetch = _f[1];
285
+ var _g = useState(0), loadingProgress = _g[0], setProgress = _g[1];
262
286
  var memoizedData = useMemo(function () { return data; }, [JSON.stringify(data)]);
263
287
  var mergedData = useMemo(function () { return (__assign(__assign({}, (defaultData !== null && defaultData !== void 0 ? defaultData : {})), (memoizedData !== null && memoizedData !== void 0 ? memoizedData : {}))); }, [defaultData, memoizedData]);
264
288
  var simulateProgress = useCallback(function () {
@@ -277,6 +301,7 @@ export function useQuery(query, data, enabled) {
277
301
  return;
278
302
  setIsLoading(true);
279
303
  simulateProgress();
304
+ setPushNotice(null);
280
305
  var abortController = new AbortController();
281
306
  client
282
307
  .request(query, mergedData, defaultUrlData, abortController.signal)
@@ -289,17 +314,18 @@ export function useQuery(query, data, enabled) {
289
314
  .then(function (parsedResponse) {
290
315
  setResponse(parsedResponse);
291
316
  setError(null);
317
+ setPushNotice(null);
292
318
  setProgress(100);
293
319
  })
294
320
  .catch(function (requestError) {
295
- if (requestError.name !== 'AbortError') {
296
- // Se o erro tem push === true, não tratar como erro (caso esperado)
297
- if (isErrorWithPush(requestError)) {
298
- // Tratar como sucesso (sem erro)
321
+ if (classifyRequestError(requestError) !== 'aborted') {
322
+ if (isErrorWithPushFlag(requestError)) {
299
323
  setError(null);
324
+ setPushNotice(pushNoticeFromError(requestError));
300
325
  setProgress(100);
301
326
  }
302
327
  else {
328
+ setPushNotice(null);
303
329
  setError(requestError instanceof Error
304
330
  ? requestError
305
331
  : new Error(String(requestError)));
@@ -340,6 +366,7 @@ export function useQuery(query, data, enabled) {
340
366
  return {
341
367
  response: response,
342
368
  error: error,
369
+ pushNotice: pushNotice,
343
370
  isLoading: isLoading,
344
371
  loadingProgress: loadingProgress,
345
372
  refetch: refetch
@@ -365,10 +392,8 @@ export function useMutation(query, data) {
365
392
  })
366
393
  .then(function (document) { return setResponse(document); })
367
394
  .catch(function (requestError) {
368
- if (requestError.name !== 'AbortError') {
369
- // Se o erro tem push === true, não tratar como erro (caso esperado)
370
- if (isErrorWithPush(requestError)) {
371
- // Tratar como sucesso (sem erro)
395
+ if (classifyRequestError(requestError) !== 'aborted') {
396
+ if (isErrorWithPushFlag(requestError)) {
372
397
  setError(null);
373
398
  }
374
399
  else {
@@ -406,10 +431,8 @@ export function useFetch(query) {
406
431
  return document;
407
432
  })
408
433
  .catch(function (requestError) {
409
- if (requestError.name !== 'AbortError') {
410
- // Se o erro tem push === true, não tratar como erro (caso esperado)
411
- if (isErrorWithPush(requestError)) {
412
- // Tratar como sucesso (sem erro)
434
+ if (classifyRequestError(requestError) !== 'aborted') {
435
+ if (isErrorWithPushFlag(requestError)) {
413
436
  setError(null);
414
437
  }
415
438
  else {
@@ -442,7 +465,8 @@ export function query(query) {
442
465
  progress: 0,
443
466
  activeRequests: 0,
444
467
  showLoadingBar: false,
445
- warningMessage: null
468
+ warningMessage: null,
469
+ pushNotice: null
446
470
  });
447
471
  return Object.assign(RequestContext, {
448
472
  Request: CustomProvider(RequestContext, query)
@@ -1,6 +1,6 @@
1
1
  import { __assign } from "tslib";
2
2
  // src/contexts/createDataContext.tsx
3
- import React, { createContext, useContext, useState } from 'react';
3
+ import React, { createContext, useCallback, useContext, useState } from 'react';
4
4
  function createDataContext(defaultValue) {
5
5
  if (defaultValue === void 0) { defaultValue = {}; }
6
6
  var DataContext = createContext({
@@ -25,12 +25,12 @@ function createDataContext(defaultValue) {
25
25
  var DataProvider = function (_a) {
26
26
  var children = _a.children;
27
27
  var _b = useState(createProxy(defaultValue)), data = _b[0], setData = _b[1];
28
- var updateData = function (update) {
28
+ var updateData = useCallback(function (update) {
29
29
  setData(function (prevData) {
30
30
  var newState = typeof update === 'function' ? update(prevData) : update;
31
31
  return createProxy(__assign(__assign({}, prevData), newState));
32
32
  });
33
- };
33
+ }, []);
34
34
  return (React.createElement(DataContext.Provider, { value: { data: data, setData: updateData } }, children));
35
35
  };
36
36
  var useData = function () { return useContext(DataContext); };
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare function ManualPushSectionPreview(): React.JSX.Element;
@@ -0,0 +1,42 @@
1
+ import React, { useContext } from 'react';
2
+ import { ThemeProvider } from 'styled-components';
3
+ import GlobalStyle from '../styles/globalStyle';
4
+ import theme from '../styles/theme';
5
+ import Section from '../components/section';
6
+ import { Queries, RequestDefaultsContext, WebService } from '../components/webservice';
7
+ function readMockMessage() {
8
+ var _a;
9
+ var q = new URLSearchParams(window.location.search);
10
+ return (((_a = q.get('devPushMsg')) === null || _a === void 0 ? void 0 : _a.trim()) ||
11
+ 'Exceção simulada com push=true (teste manual).');
12
+ }
13
+ function buildMockWebService() {
14
+ var message = readMockMessage();
15
+ return {
16
+ request: function () {
17
+ return Promise.reject(Object.assign(new Error(message), { push: true }));
18
+ }
19
+ };
20
+ }
21
+ function FinderMockSection() {
22
+ var ctx = useContext(Queries.Finder);
23
+ if (!ctx)
24
+ return null;
25
+ return (React.createElement(Section, { ctx: ctx, title: "Finder \u2014 mock push=true", subtitle: "Query real: FINDER.BILLING; resposta: reject com push (s\u00F3 dev)" }));
26
+ }
27
+ export function ManualPushSectionPreview() {
28
+ return (React.createElement(ThemeProvider, { theme: theme },
29
+ React.createElement(GlobalStyle, null),
30
+ React.createElement("div", { style: { padding: 24, maxWidth: 720 } },
31
+ React.createElement("p", { style: { marginBottom: 16, fontSize: 14, opacity: 0.85 } },
32
+ "Par\u00E2metros: ",
33
+ React.createElement("code", null, "?devPushSection=1"),
34
+ " e opcionalmente",
35
+ ' ',
36
+ React.createElement("code", null, "devPushMsg=..."),
37
+ " (mensagem na exce\u00E7\u00E3o)."),
38
+ React.createElement(WebService.Provider, { value: buildMockWebService() },
39
+ React.createElement(RequestDefaultsContext.Provider, { value: {} },
40
+ React.createElement(Queries.Finder.Request, { data: { documento: '00000000000100' } },
41
+ React.createElement(FinderMockSection, null)))))));
42
+ }
@@ -1,6 +1,7 @@
1
1
  export declare function useSafeQuery<T>(query: string, params: Record<string, any>, skip?: boolean): {
2
2
  response: import("../components/webservice").ParsedResponse<T> | null;
3
3
  error: Error | null;
4
+ pushNotice: import("../components/webservice").PushNotice | null;
4
5
  isLoading: boolean;
5
6
  loadingProgress: number;
6
7
  refetch: () => void;
@@ -0,0 +1,9 @@
1
+ /**
2
+ * Classificação única de erros de request (transporte / webservice).
3
+ * Mantém semântica alinhada ao contrato Credithub (ex.: `push=true` = exceção esperada).
4
+ */
5
+ export type RequestErrorKind = 'aborted' | 'push_expected' | 'real_error';
6
+ export declare function isErrorWithPushFlag(error: unknown): boolean;
7
+ export declare function classifyRequestError(error: unknown): RequestErrorKind;
8
+ /** True quando o upstream deve bloquear refetch automático (erro real, não push nem abort). */
9
+ export declare function isRealRequestFailure(error: unknown): boolean;
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Classificação única de erros de request (transporte / webservice).
3
+ * Mantém semântica alinhada ao contrato Credithub (ex.: `push=true` = exceção esperada).
4
+ */
5
+ export function isErrorWithPushFlag(error) {
6
+ if (error && typeof error === 'object') {
7
+ return error.push === true;
8
+ }
9
+ return false;
10
+ }
11
+ export function classifyRequestError(error) {
12
+ if (error &&
13
+ typeof error === 'object' &&
14
+ 'name' in error &&
15
+ error.name === 'AbortError') {
16
+ return 'aborted';
17
+ }
18
+ if (isErrorWithPushFlag(error)) {
19
+ return 'push_expected';
20
+ }
21
+ return 'real_error';
22
+ }
23
+ /** True quando o upstream deve bloquear refetch automático (erro real, não push nem abort). */
24
+ export function isRealRequestFailure(error) {
25
+ return classifyRequestError(error) === 'real_error';
26
+ }