@credithub/harlan-components 1.111.2 → 1.112.1

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.
@@ -58,13 +58,17 @@ var __rest = (this && this.__rest) || function (s, e) {
58
58
  };
59
59
  import { useGlobalData } from '../../contexts/globalDataContext';
60
60
  import { formatMoney } from '../../utils/number';
61
- import { openFormThenRedirect } from '../../utils/protestosp';
61
+ import { isProtestoSPByNmChave } from '../../utils/protestoUf';
62
62
  import { formatDocument } from '../../utils/string';
63
63
  import React, { memo, useCallback, useContext, useEffect, useMemo, useState } from 'react';
64
64
  import AddItemField from '../common/addItem';
65
65
  import Button from '../common/button';
66
+ import ModalInstrumentoProtestoSP from '../common/modalInstrumentoProtestoSP';
66
67
  import { ResultContent } from '../interface/result';
67
68
  import { WebService } from '../webservice';
69
+ import InstrumentoDiscoveryConfirmModal from './instrumento/InstrumentoDiscoveryConfirmModal';
70
+ import InstrumentoEmailStatusModal from './instrumento/InstrumentoEmailStatusModal';
71
+ import { useInstrumento } from './instrumento/useInstrumento';
68
72
  // Throttling mechanism for API requests
69
73
  var activeRequests = 0;
70
74
  var MAX_CONCURRENT_REQUESTS = 2;
@@ -279,6 +283,12 @@ export var Instrumento = function (_a) {
279
283
  var checkedInstruments = protestosData.checkedInstruments || {};
280
284
  var instrumentCache = protestosData.instrumentCache || {};
281
285
  var normalizedKey = useMemo(function () { return normalizeInstrumentKey(nm_chave); }, [nm_chave]);
286
+ // Hook para gerenciar fluxo de instrumento (fase mockada)
287
+ var instrumentoHook = useInstrumento({
288
+ nmChave: normalizedKey || '',
289
+ cpfCnpj: cpfCnpj || '',
290
+ client: client
291
+ });
282
292
  if (!nm_chave)
283
293
  return null;
284
294
  var hasFailedBefore = failedInstruments[nm_chave] === true;
@@ -314,6 +324,7 @@ export var Instrumento = function (_a) {
314
324
  var _c = useState(deriveErrorKind), errorKind = _c[0], setErrorKind = _c[1];
315
325
  var _d = useState(false), isLoading = _d[0], setIsLoading = _d[1];
316
326
  var _e = useState(shouldPrefetch), isPrefetching = _e[0], setIsPrefetching = _e[1];
327
+ var _f = useState(false), isDiscoveryConfirmOpen = _f[0], setIsDiscoveryConfirmOpen = _f[1];
317
328
  useEffect(function () {
318
329
  setErrorKind(deriveErrorKind());
319
330
  }, [deriveErrorKind]);
@@ -402,21 +413,25 @@ export var Instrumento = function (_a) {
402
413
  setData,
403
414
  shouldPrefetch
404
415
  ]);
405
- var isDisabled = isLoading || isPrefetching || errorKind !== null;
416
+ // Mantém o botão clicável em `not-found` para permitir solicitar por e-mail
417
+ var isDisabled = isLoading ||
418
+ isPrefetching ||
419
+ errorKind === 'invalid-key' ||
420
+ errorKind === 'missing-doc';
406
421
  var getTooltipMessage = function () {
407
422
  if (errorKind === 'missing-doc')
408
423
  return 'Documento não disponível para consulta';
409
424
  if (errorKind === 'invalid-key')
410
425
  return 'Chave de instrumento inválida';
411
426
  if (errorKind === 'not-found')
412
- return 'Instrumento não localizado no sistema';
427
+ return 'PDF indisponível. Você pode solicitar por e-mail.';
413
428
  if (isPrefetching)
414
429
  return 'Verificando disponibilidade do instrumento...';
415
430
  return '';
416
431
  };
417
432
  var getButtonLabel = function () {
418
- if (errorKind === 'not-found')
419
- return 'Instrumento não Localizado';
433
+ if (errorKind === 'not-found' && !isProtestoSPByNmChave(normalizedKey))
434
+ return 'Solicitar por e-mail';
420
435
  if (errorKind === 'invalid-key' || errorKind === 'missing-doc')
421
436
  return 'Instrumento Indisponível';
422
437
  return 'Instrumento';
@@ -428,73 +443,100 @@ export var Instrumento = function (_a) {
428
443
  return;
429
444
  pdfWindow.document.write("<iframe width='100%' height='100%' src='data:application/pdf;base64,".concat(base64, "'></iframe>"));
430
445
  };
431
- return (React.createElement("span", { title: tooltipMessage, style: { display: 'inline-block' } },
432
- React.createElement(Button, { isLoading: isLoading, onClick: function () { return __awaiter(void 0, void 0, void 0, function () {
433
- var request_1, e_1, failure_2;
434
- return __generator(this, function (_a) {
435
- switch (_a.label) {
436
- case 0:
437
- if (isDisabled)
438
- return [2 /*return*/];
439
- if (/^35/.test(normalizedKey)) {
446
+ var isSP = isProtestoSPByNmChave(normalizedKey);
447
+ return (React.createElement(React.Fragment, null,
448
+ React.createElement("span", { title: tooltipMessage, style: { display: 'inline-block' } },
449
+ React.createElement(Button, { isLoading: isLoading || instrumentoHook.isProcessandoDescoberta, onClick: function () { return __awaiter(void 0, void 0, void 0, function () {
450
+ var request_1, e_1, failure_2;
451
+ return __generator(this, function (_a) {
452
+ switch (_a.label) {
453
+ case 0:
454
+ if (isDisabled)
455
+ return [2 /*return*/];
456
+ // Fluxo SP: abre modal para Livro/Folha
457
+ if (isSP) {
458
+ instrumentoHook.openModalSP();
459
+ return [2 /*return*/];
460
+ }
461
+ // Se já sabemos que o PDF está indisponível, oferecemos o fluxo por e-mail
462
+ if (errorKind === 'not-found') {
463
+ setIsDiscoveryConfirmOpen(true);
464
+ return [2 /*return*/];
465
+ }
466
+ // Fluxo não-SP: tenta abrir PDF se disponível
467
+ if (cachedInstrument) {
468
+ openInstrumentPdf(cachedInstrument);
469
+ return [2 /*return*/];
470
+ }
471
+ // Tenta buscar PDF do backend
440
472
  setIsLoading(true);
441
- try {
442
- openFormThenRedirect(normalizedKey, cpfCnpj);
473
+ _a.label = 1;
474
+ case 1:
475
+ _a.trys.push([1, 4, 5, 6]);
476
+ return [4 /*yield*/, client.request("SELECT FROM 'IEPTB'.'PDF'", {
477
+ nm_chave: normalizedKey,
478
+ documento: cpfCnpj
479
+ })];
480
+ case 2: return [4 /*yield*/, (_a.sent()).json()];
481
+ case 3:
482
+ request_1 = _a.sent();
483
+ if (!(request_1 === null || request_1 === void 0 ? void 0 : request_1.instrumentoProtesto)) {
484
+ throw new Error('Instrumento não retornado pela API');
443
485
  }
444
- finally {
445
- setIsLoading(false);
486
+ openInstrumentPdf(request_1.instrumentoProtesto);
487
+ setData(function (prev) {
488
+ var _a, _b;
489
+ var base = prev || {};
490
+ var prevProtestosData = base.protestosData || {};
491
+ var _c = prevProtestosData.failedInstruments || {}, _d = nm_chave, _removedFailed = _c[_d], restFailed = __rest(_c, [typeof _d === "symbol" ? _d : _d + ""]);
492
+ var _e = prevProtestosData.failedInstrumentReasons || {}, _f = nm_chave, _removedReason = _e[_f], restReasons = __rest(_e, [typeof _f === "symbol" ? _f : _f + ""]);
493
+ return __assign(__assign({}, base), { protestosData: __assign(__assign({}, prevProtestosData), { failedInstruments: restFailed, failedInstrumentReasons: restReasons, instrumentCache: __assign(__assign({}, (prevProtestosData.instrumentCache || {})), (_a = {}, _a[nm_chave] = request_1.instrumentoProtesto, _a)), checkedInstruments: __assign(__assign({}, (prevProtestosData.checkedInstruments || {})), (_b = {}, _b[nm_chave] = true, _b)) }) });
494
+ });
495
+ setErrorKind(null);
496
+ return [3 /*break*/, 6];
497
+ case 4:
498
+ e_1 = _a.sent();
499
+ console.error(e_1);
500
+ failure_2 = classifyInstrumentError(e_1);
501
+ setErrorKind(failure_2);
502
+ // Quando PDF não está disponível, oferece descoberta automática com confirmação (UX)
503
+ if (failure_2 === 'not-found' && hasCpfCnpj && isValidKey) {
504
+ setIsDiscoveryConfirmOpen(true);
446
505
  }
447
- return [2 /*return*/];
448
- }
449
- if (cachedInstrument) {
450
- openInstrumentPdf(cachedInstrument);
451
- return [2 /*return*/];
452
- }
453
- setIsLoading(true);
454
- _a.label = 1;
506
+ // Persistimos falha/cache para evitar loops de prefetch
507
+ setData(function (prev) {
508
+ var _a, _b, _c;
509
+ var base = prev || {};
510
+ var prevProtestosData = base.protestosData || {};
511
+ var _d = prevProtestosData.instrumentCache || {}, _e = nm_chave, _cachedInstrument = _d[_e], restCache = __rest(_d, [typeof _e === "symbol" ? _e : _e + ""]);
512
+ return __assign(__assign({}, base), { protestosData: __assign(__assign({}, prevProtestosData), { instrumentCache: restCache, failedInstruments: __assign(__assign({}, (prevProtestosData.failedInstruments || {})), (_a = {}, _a[nm_chave] = true, _a)), checkedInstruments: __assign(__assign({}, (prevProtestosData.checkedInstruments || {})), (_b = {}, _b[nm_chave] = true, _b)), failedInstrumentReasons: __assign(__assign({}, (prevProtestosData.failedInstrumentReasons || {})), (_c = {}, _c[nm_chave] = failure_2, _c)) }) });
513
+ });
514
+ return [3 /*break*/, 6];
515
+ case 5:
516
+ setIsLoading(false);
517
+ return [7 /*endfinally*/];
518
+ case 6: return [2 /*return*/];
519
+ }
520
+ });
521
+ }); }, disabled: isDisabled }, getButtonLabel())),
522
+ React.createElement(ModalInstrumentoProtestoSP, { isOpen: instrumentoHook.isModalSPOpen, onClose: instrumentoHook.closeModalSP, onEnviarEmail: instrumentoHook.handleEnviarEmail, isEnviandoEmail: instrumentoHook.isEnviandoEmail }),
523
+ React.createElement(InstrumentoEmailStatusModal, { isOpen: instrumentoHook.isEmailModalOpen, onClose: instrumentoHook.closeEmailModal, message: instrumentoHook.emailMessage, title: instrumentoHook.emailTitle }),
524
+ React.createElement(InstrumentoDiscoveryConfirmModal, { isOpen: isDiscoveryConfirmOpen, onClose: function () { return setIsDiscoveryConfirmOpen(false); }, isLoading: instrumentoHook.isProcessandoDescoberta, onConfirm: function () { return __awaiter(void 0, void 0, void 0, function () {
525
+ return __generator(this, function (_a) {
526
+ switch (_a.label) {
527
+ case 0:
528
+ _a.trys.push([0, , 2, 3]);
529
+ return [4 /*yield*/, instrumentoHook.handleDescobertaAutomatica()];
455
530
  case 1:
456
- _a.trys.push([1, 4, 5, 6]);
457
- return [4 /*yield*/, client.request("SELECT FROM 'IEPTB'.'PDF'", {
458
- nm_chave: normalizedKey,
459
- documento: cpfCnpj
460
- })];
461
- case 2: return [4 /*yield*/, (_a.sent()).json()];
462
- case 3:
463
- request_1 = _a.sent();
464
- if (!(request_1 === null || request_1 === void 0 ? void 0 : request_1.instrumentoProtesto)) {
465
- throw new Error('Instrumento não retornado pela API');
466
- }
467
- openInstrumentPdf(request_1.instrumentoProtesto);
468
- setData(function (prev) {
469
- var _a, _b;
470
- var base = prev || {};
471
- var prevProtestosData = base.protestosData || {};
472
- var _c = prevProtestosData.failedInstruments || {}, _d = nm_chave, _removedFailed = _c[_d], restFailed = __rest(_c, [typeof _d === "symbol" ? _d : _d + ""]);
473
- var _e = prevProtestosData.failedInstrumentReasons || {}, _f = nm_chave, _removedReason = _e[_f], restReasons = __rest(_e, [typeof _f === "symbol" ? _f : _f + ""]);
474
- return __assign(__assign({}, base), { protestosData: __assign(__assign({}, prevProtestosData), { failedInstruments: restFailed, failedInstrumentReasons: restReasons, instrumentCache: __assign(__assign({}, (prevProtestosData.instrumentCache || {})), (_a = {}, _a[nm_chave] = request_1.instrumentoProtesto, _a)), checkedInstruments: __assign(__assign({}, (prevProtestosData.checkedInstruments || {})), (_b = {}, _b[nm_chave] = true, _b)) }) });
475
- });
476
- setErrorKind(null);
477
- return [3 /*break*/, 6];
478
- case 4:
479
- e_1 = _a.sent();
480
- console.error(e_1);
481
- failure_2 = classifyInstrumentError(e_1);
482
- setErrorKind(failure_2);
483
- setData(function (prev) {
484
- var _a, _b, _c;
485
- var base = prev || {};
486
- var prevProtestosData = base.protestosData || {};
487
- var _d = prevProtestosData.instrumentCache || {}, _e = nm_chave, _cachedInstrument = _d[_e], restCache = __rest(_d, [typeof _e === "symbol" ? _e : _e + ""]);
488
- return __assign(__assign({}, base), { protestosData: __assign(__assign({}, prevProtestosData), { instrumentCache: restCache, failedInstruments: __assign(__assign({}, (prevProtestosData.failedInstruments || {})), (_a = {}, _a[nm_chave] = true, _a)), checkedInstruments: __assign(__assign({}, (prevProtestosData.checkedInstruments || {})), (_b = {}, _b[nm_chave] = true, _b)), failedInstrumentReasons: __assign(__assign({}, (prevProtestosData.failedInstrumentReasons || {})), (_c = {}, _c[nm_chave] = failure_2, _c)) }) });
489
- });
490
- return [3 /*break*/, 6];
491
- case 5:
492
- setIsLoading(false);
531
+ _a.sent();
532
+ return [3 /*break*/, 3];
533
+ case 2:
534
+ setIsDiscoveryConfirmOpen(false);
493
535
  return [7 /*endfinally*/];
494
- case 6: return [2 /*return*/];
536
+ case 3: return [2 /*return*/];
495
537
  }
496
538
  });
497
- }); }, disabled: isDisabled }, getButtonLabel())));
539
+ }); } })));
498
540
  };
499
541
  export var ProtestosList = function (_a) {
500
542
  var protestos = _a.protestos;
@@ -5,7 +5,10 @@ var __makeTemplateObject = (this && this.__makeTemplateObject) || function (cook
5
5
  // src/styles/globalStyle.tsx
6
6
  import React from 'react';
7
7
  import { createGlobalStyle } from 'styled-components';
8
- var GlobalStyle = createGlobalStyle(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n /* Reset + fonte padr\u00E3o para toda a aplica\u00E7\u00E3o (inclui modais e portais) */\n *, *::before, *::after {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n font-family: 'Open Sans Condensed', sans-serif;\n }\n\n body {\n -webkit-font-smoothing: antialiased;\n }\n\n /* Oculta bot\u00F5es e tooltips na impress\u00E3o */\n @media print {\n button,\n [role=\"button\"],\n [class*=\"Button\"],\n [class^=\"Button\"],\n [class*=\"btn\"],\n [class^=\"btn\"],\n .button,\n .btn,\n [class*=\"tooltip\"],\n [class*=\"Tooltip\"],\n [data-tooltip] {\n display: none !important;\n visibility: hidden !important;\n }\n }\n\n body.print-mode,\n body[data-print-mode='true'] {\n button,\n [role=\"button\"],\n [class*=\"Button\"],\n [class^=\"Button\"],\n [class*=\"btn\"],\n [class^=\"btn\"],\n .button,\n .btn,\n [class*=\"tooltip\"],\n [class*=\"Tooltip\"],\n [data-tooltip] {\n display: none !important;\n visibility: hidden !important;\n }\n }\n\n /* Anima\u00E7\u00F5es utilit\u00E1rias */\n @keyframes highlight {\n from {\n background-color: rgba(255, 215, 0, 0.35);\n }\n to {\n background-color: transparent;\n }\n }\n\n .highlighted-process {\n animation: highlight 3s ease-out forwards !important;\n }\n\n @keyframes blueHighlight {\n from {\n background-color: rgba(0, 122, 255, 0.35);\n }\n to {\n background-color: rgba(0, 122, 255, 0.15);\n }\n }\n\n .blue-highlighted-process {\n animation: blueHighlight 2.5s ease-in-out;\n background-color: rgba(0, 122, 255, 0.15);\n transition: background-color 0.3s ease-in-out;\n }\n"], ["\n /* Reset + fonte padr\u00E3o para toda a aplica\u00E7\u00E3o (inclui modais e portais) */\n *, *::before, *::after {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n font-family: 'Open Sans Condensed', sans-serif;\n }\n\n body {\n -webkit-font-smoothing: antialiased;\n }\n\n /* Oculta bot\u00F5es e tooltips na impress\u00E3o */\n @media print {\n button,\n [role=\"button\"],\n [class*=\"Button\"],\n [class^=\"Button\"],\n [class*=\"btn\"],\n [class^=\"btn\"],\n .button,\n .btn,\n [class*=\"tooltip\"],\n [class*=\"Tooltip\"],\n [data-tooltip] {\n display: none !important;\n visibility: hidden !important;\n }\n }\n\n body.print-mode,\n body[data-print-mode='true'] {\n button,\n [role=\"button\"],\n [class*=\"Button\"],\n [class^=\"Button\"],\n [class*=\"btn\"],\n [class^=\"btn\"],\n .button,\n .btn,\n [class*=\"tooltip\"],\n [class*=\"Tooltip\"],\n [data-tooltip] {\n display: none !important;\n visibility: hidden !important;\n }\n }\n\n /* Anima\u00E7\u00F5es utilit\u00E1rias */\n @keyframes highlight {\n from {\n background-color: rgba(255, 215, 0, 0.35);\n }\n to {\n background-color: transparent;\n }\n }\n\n .highlighted-process {\n animation: highlight 3s ease-out forwards !important;\n }\n\n @keyframes blueHighlight {\n from {\n background-color: rgba(0, 122, 255, 0.35);\n }\n to {\n background-color: rgba(0, 122, 255, 0.15);\n }\n }\n\n .blue-highlighted-process {\n animation: blueHighlight 2.5s ease-in-out;\n background-color: rgba(0, 122, 255, 0.15);\n transition: background-color 0.3s ease-in-out;\n }\n"])));
8
+ var GlobalStyle = createGlobalStyle(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n /* Reset + fonte padr\u00E3o para toda a aplica\u00E7\u00E3o (inclui modais e portais) */\n *, *::before, *::after {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n font-family: ", ";\n }\n\n body {\n -webkit-font-smoothing: antialiased;\n }\n\n /* Oculta bot\u00F5es e tooltips na impress\u00E3o */\n @media print {\n button,\n [role=\"button\"],\n [class*=\"Button\"],\n [class^=\"Button\"],\n [class*=\"btn\"],\n [class^=\"btn\"],\n .button,\n .btn,\n [class*=\"tooltip\"],\n [class*=\"Tooltip\"],\n [data-tooltip] {\n display: none !important;\n visibility: hidden !important;\n }\n }\n\n body.print-mode,\n body[data-print-mode='true'] {\n button,\n [role=\"button\"],\n [class*=\"Button\"],\n [class^=\"Button\"],\n [class*=\"btn\"],\n [class^=\"btn\"],\n .button,\n .btn,\n [class*=\"tooltip\"],\n [class*=\"Tooltip\"],\n [data-tooltip] {\n display: none !important;\n visibility: hidden !important;\n }\n }\n\n /* Anima\u00E7\u00F5es utilit\u00E1rias */\n @keyframes highlight {\n from {\n background-color: rgba(255, 215, 0, 0.35);\n }\n to {\n background-color: transparent;\n }\n }\n\n .highlighted-process {\n animation: highlight 3s ease-out forwards !important;\n }\n\n @keyframes blueHighlight {\n from {\n background-color: rgba(0, 122, 255, 0.35);\n }\n to {\n background-color: rgba(0, 122, 255, 0.15);\n }\n }\n\n .blue-highlighted-process {\n animation: blueHighlight 2.5s ease-in-out;\n background-color: rgba(0, 122, 255, 0.15);\n transition: background-color 0.3s ease-in-out;\n }\n"], ["\n /* Reset + fonte padr\u00E3o para toda a aplica\u00E7\u00E3o (inclui modais e portais) */\n *, *::before, *::after {\n margin: 0;\n padding: 0;\n box-sizing: border-box;\n font-family: ", ";\n }\n\n body {\n -webkit-font-smoothing: antialiased;\n }\n\n /* Oculta bot\u00F5es e tooltips na impress\u00E3o */\n @media print {\n button,\n [role=\"button\"],\n [class*=\"Button\"],\n [class^=\"Button\"],\n [class*=\"btn\"],\n [class^=\"btn\"],\n .button,\n .btn,\n [class*=\"tooltip\"],\n [class*=\"Tooltip\"],\n [data-tooltip] {\n display: none !important;\n visibility: hidden !important;\n }\n }\n\n body.print-mode,\n body[data-print-mode='true'] {\n button,\n [role=\"button\"],\n [class*=\"Button\"],\n [class^=\"Button\"],\n [class*=\"btn\"],\n [class^=\"btn\"],\n .button,\n .btn,\n [class*=\"tooltip\"],\n [class*=\"Tooltip\"],\n [data-tooltip] {\n display: none !important;\n visibility: hidden !important;\n }\n }\n\n /* Anima\u00E7\u00F5es utilit\u00E1rias */\n @keyframes highlight {\n from {\n background-color: rgba(255, 215, 0, 0.35);\n }\n to {\n background-color: transparent;\n }\n }\n\n .highlighted-process {\n animation: highlight 3s ease-out forwards !important;\n }\n\n @keyframes blueHighlight {\n from {\n background-color: rgba(0, 122, 255, 0.35);\n }\n to {\n background-color: rgba(0, 122, 255, 0.15);\n }\n }\n\n .blue-highlighted-process {\n animation: blueHighlight 2.5s ease-in-out;\n background-color: rgba(0, 122, 255, 0.15);\n transition: background-color 0.3s ease-in-out;\n }\n"])), function (_a) {
9
+ var theme = _a.theme;
10
+ return theme.typography.defaultFontFamily;
11
+ });
9
12
  // Componente que aplica os estilos globais da aplicação.
10
13
  // A fonte "Open Sans Condensed" já é carregada via index.html.
11
14
  var GlobalStyleProvider = function () { return (React.createElement(React.Fragment, null,
@@ -16,6 +16,7 @@ declare const theme: {
16
16
  cinzaClaro: string;
17
17
  cinzaBase: string;
18
18
  cinzaBackground: string;
19
+ cinzaMedio: string;
19
20
  cinzaEscuro: string;
20
21
  prata: string;
21
22
  likeButton: string;
@@ -16,6 +16,7 @@ var theme = {
16
16
  cinzaClaro: 'rgba(209, 209, 209, 1)',
17
17
  cinzaBase: 'rgba(245, 245, 245, 1)',
18
18
  cinzaBackground: '#efefef',
19
+ cinzaMedio: 'rgba(120, 120, 120, 1)',
19
20
  cinzaEscuro: 'rgba(53, 53, 53, 1)',
20
21
  prata: 'rgba(121, 129, 125, 1)',
21
22
  likeButton: '#007aff',
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Heurística atual para inferir UF do protesto.
3
+ *
4
+ * Contexto: o payload de protestos (CENPROT) que consumimos hoje não expõe UF/cidade do cartório,
5
+ * então a única pista disponível na UI é a `nm_chave`.
6
+ *
7
+ * Na prática, a `nm_chave` costuma começar com o código IBGE da UF (ex: "35" = São Paulo).
8
+ * Quando o backend passar UF explicitamente, esta lógica deve ser substituída por um campo confiável.
9
+ */
10
+ export declare const isProtestoSPByNmChave: (nmChave?: string) => boolean;
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Heurística atual para inferir UF do protesto.
3
+ *
4
+ * Contexto: o payload de protestos (CENPROT) que consumimos hoje não expõe UF/cidade do cartório,
5
+ * então a única pista disponível na UI é a `nm_chave`.
6
+ *
7
+ * Na prática, a `nm_chave` costuma começar com o código IBGE da UF (ex: "35" = São Paulo).
8
+ * Quando o backend passar UF explicitamente, esta lógica deve ser substituída por um campo confiável.
9
+ */
10
+ var digitsOnly = function (value) { return (value ? value.replace(/\D+/g, '') : ''); };
11
+ export var isProtestoSPByNmChave = function (nmChave) {
12
+ var key = digitsOnly(nmChave);
13
+ if (!key)
14
+ return false;
15
+ // "35" é o código IBGE de São Paulo
16
+ return key.startsWith('35');
17
+ };