zenit-sdk 0.1.8 → 0.2.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.
@@ -640,6 +640,152 @@ function useGeolocation(options) {
640
640
 
641
641
  // src/react/map/map-utils.ts
642
642
  import L2 from "leaflet";
643
+
644
+ // src/config/modalWhitelist.ts
645
+ function normalizeKey(value) {
646
+ return value.normalize("NFD").replace(/\p{Diacritic}/gu, "").replace(/[_\s-]+/g, "").toLowerCase().trim();
647
+ }
648
+ var CLIENTE_MODAL_WHITELIST = [
649
+ {
650
+ id: "nombre_cliente",
651
+ label: "Nombre del Cliente",
652
+ aliases: ["nombre_del_cliente", "nombre cliente", "nombre_del_cliente ", "NOMBRE_CLIENTE"]
653
+ },
654
+ {
655
+ id: "dpi",
656
+ label: "DPI",
657
+ aliases: ["dpi", "DPI"]
658
+ },
659
+ {
660
+ id: "kpi",
661
+ label: "Estado",
662
+ aliases: ["kpi", "KPI"],
663
+ hint: "kpi_badge"
664
+ },
665
+ {
666
+ id: "tel_principal",
667
+ label: "Tel\xE9fono",
668
+ aliases: ["tel_principal", "tel principal", "telefono", "telefono_principal", "TEL_PRINCIPAL"],
669
+ hint: "phone_link"
670
+ },
671
+ {
672
+ id: "capital_concedido",
673
+ label: "Capital Concedido",
674
+ aliases: ["capital_concedido", "capital concedido", "CAPITAL_CONCEDIDO"]
675
+ },
676
+ {
677
+ id: "mora",
678
+ label: "Monto en Mora",
679
+ aliases: ["mora", "MORA"],
680
+ hint: "mora_alert"
681
+ },
682
+ {
683
+ id: "etapa",
684
+ label: "Etapa del Cr\xE9dito",
685
+ aliases: ["etapa", "ETAPA"]
686
+ },
687
+ {
688
+ id: "prestamo",
689
+ label: "No. de Pr\xE9stamo",
690
+ aliases: ["prestamo", "prestamo_id", "no_prestamo", "numero_prestamo", "PRESTAMO"]
691
+ },
692
+ {
693
+ id: "sucursal",
694
+ label: "Sucursal",
695
+ aliases: ["sucursal", "nombre_sucursal", "nombre sucursal", "SUCURSAL"]
696
+ }
697
+ ];
698
+ var SECTOR_MODAL_WHITELIST = [
699
+ { id: "sector", label: "Sector", aliases: ["nom_sector", "NOM_SECTOR", "sector", "SECTOR"] },
700
+ { id: "promotor", label: "Promotor", aliases: ["promotor", "PROMOTOR"] },
701
+ { id: "capital_total", label: "Capital Total", aliases: ["capital_total", "capital total", "CAPITAL_TOTAL"] },
702
+ {
703
+ id: "total_capital_mora",
704
+ label: "Total Capital Mora",
705
+ aliases: ["total_capital_mora", "total capital mora", "TOTAL_CAPITAL_MORA"]
706
+ },
707
+ {
708
+ id: "tendencia_mora",
709
+ label: "Tendencia Mora",
710
+ aliases: ["tendencia_mora", "tendencia mora", "TENDENCIA_MORA"],
711
+ hint: "trend_icon"
712
+ },
713
+ {
714
+ id: "tendencia_capital",
715
+ label: "Tendencia Capital",
716
+ aliases: ["tendencia_capital", "tendencia capital", "TENDENCIA_CAPITAL"],
717
+ hint: "trend_icon"
718
+ },
719
+ {
720
+ id: "tendencia_castigos",
721
+ label: "Tendencia Castigos",
722
+ aliases: ["tendencia_castigos", "tendencia castigos", "TENDENCIA_CASTIGOS"],
723
+ hint: "trend_icon"
724
+ },
725
+ {
726
+ id: "impacto_sector",
727
+ label: "Impacto Sector",
728
+ aliases: ["impacto_sector", "impacto sector", "IMPACTO_SECTOR"]
729
+ },
730
+ {
731
+ id: "total_clientes_sector",
732
+ label: "Total Clientes Sector",
733
+ aliases: ["total_clientes_sector", "total clientes sector", "TOTAL_CLIENTES_SECTOR"]
734
+ },
735
+ {
736
+ id: "total_clientes_sanos",
737
+ label: "Total Clientes Sanos",
738
+ aliases: ["total_clientes_sanos", "total clientes sanos", "TOTAL_CLIENTES_SANOS"]
739
+ },
740
+ {
741
+ id: "total_clientes_morosos",
742
+ label: "Total Clientes Morosos",
743
+ aliases: ["total_clientes_morosos", "total clientes morosos", "TOTAL_CLIENTES_MOROSOS"]
744
+ },
745
+ {
746
+ id: "total_clientes_castigados",
747
+ label: "Total Clientes Castigados",
748
+ aliases: ["total_clientes_castigados", "total clientes castigados", "TOTAL_CLIENTES_CASTIGADOS"]
749
+ },
750
+ {
751
+ id: "total_clientes_nuevos",
752
+ label: "Total Clientes Nuevos",
753
+ aliases: ["total_clientes_nuevos", "total clientes nuevos", "TOTAL_CLIENTES_NUEVOS"]
754
+ },
755
+ {
756
+ id: "total_clientes_salidos",
757
+ label: "Total Clientes Salidos",
758
+ aliases: ["total_clientes_salidos", "total clientes salidos", "TOTAL_CLIENTES_SALIDOS"]
759
+ },
760
+ { id: "insights", label: "Insights", aliases: ["insights", "INSIGHTS"], hint: "collapsible" },
761
+ {
762
+ id: "recomendaciones",
763
+ label: "Recomendaciones",
764
+ aliases: ["recomendaciones", "RECOMENDACIONES"],
765
+ hint: "collapsible"
766
+ }
767
+ ];
768
+ function applyModalWhitelist(rawData, whitelist) {
769
+ const keyByNormalized = /* @__PURE__ */ new Map();
770
+ Object.keys(rawData ?? {}).forEach((rawKey) => {
771
+ const normalized = normalizeKey(rawKey);
772
+ if (!normalized || keyByNormalized.has(normalized)) return;
773
+ keyByNormalized.set(normalized, rawKey);
774
+ });
775
+ return whitelist.map(({ id, label, hint, aliases }) => {
776
+ const candidates = [...aliases, id];
777
+ for (const candidate of candidates) {
778
+ const matchedKey = keyByNormalized.get(normalizeKey(candidate));
779
+ if (!matchedKey) continue;
780
+ const value = rawData[matchedKey];
781
+ if (value === null || value === void 0) continue;
782
+ return { id, label, value, hint: hint ?? null, matchedKey };
783
+ }
784
+ return null;
785
+ }).filter((entry) => Boolean(entry));
786
+ }
787
+
788
+ // src/react/map/map-utils.ts
643
789
  var POPUP_STYLE_ID = "zenit-leaflet-popup-styles";
644
790
  var POPUP_EXCLUDED_KEYS = /* @__PURE__ */ new Set(["geom", "geometry", "_private"]);
645
791
  var POPUP_TITLE_KEYS = ["id", "nombre", "name", "title", "titulo", "cluster"];
@@ -899,6 +1045,10 @@ function createPopupContent(properties) {
899
1045
  const descriptionHtml = header.description ? `<div style="margin-bottom:10px; padding:8px 10px; background:#f8fafc; border-left:3px solid #38bdf8; border-radius:6px; color:#334155; font-size:12px;">${escapeHtml(
900
1046
  header.description.value
901
1047
  )}</div>` : "";
1048
+ const whitelistedRows = buildWhitelistedRows(properties, { colorBar, headerHtml, descriptionHtml });
1049
+ if (whitelistedRows) {
1050
+ return whitelistedRows;
1051
+ }
902
1052
  const rowsHtml = entries.map(([key, value]) => {
903
1053
  const label = escapeHtml(formatLabel(key));
904
1054
  const normalizedKey = key.trim().toLowerCase();
@@ -915,6 +1065,74 @@ function createPopupContent(properties) {
915
1065
  }).join("");
916
1066
  return `<div>${colorBar}${headerHtml}${descriptionHtml}${rowsHtml}</div>`;
917
1067
  }
1068
+ function buildWhitelistedRows(properties, headerSections) {
1069
+ const selection = selectModalWhitelist(properties);
1070
+ if (!selection) {
1071
+ logModalWhitelistDebug({
1072
+ modalType: "generic",
1073
+ properties,
1074
+ entries: [],
1075
+ whitelist: null,
1076
+ fallbackToGeneric: true
1077
+ });
1078
+ return null;
1079
+ }
1080
+ const { whitelist, modalType } = selection;
1081
+ const entries = applyModalWhitelist(properties, whitelist);
1082
+ if (entries.length === 0) {
1083
+ logModalWhitelistDebug({
1084
+ modalType,
1085
+ properties,
1086
+ entries,
1087
+ whitelist,
1088
+ fallbackToGeneric: true
1089
+ });
1090
+ return null;
1091
+ }
1092
+ logModalWhitelistDebug({
1093
+ modalType,
1094
+ properties,
1095
+ entries,
1096
+ whitelist,
1097
+ fallbackToGeneric: false
1098
+ });
1099
+ const rowsHtml = entries.map(({ label, value }) => {
1100
+ const valueHtml = renderPopupValue(value);
1101
+ return `
1102
+ <div style="display:grid; grid-template-columns:minmax(90px, 35%) 1fr; gap:8px; padding:6px 0; border-bottom:1px solid #e2e8f0;">
1103
+ <div style="font-size:11px; font-weight:600; text-transform:uppercase; letter-spacing:0.04em; color:#64748b;">${escapeHtml(label)}</div>
1104
+ <div style="font-size:13px; color:#0f172a; word-break:break-word;">${valueHtml}</div>
1105
+ </div>
1106
+ `;
1107
+ }).join("");
1108
+ return `<div>${headerSections.colorBar}${headerSections.headerHtml}${headerSections.descriptionHtml}${rowsHtml}</div>`;
1109
+ }
1110
+ function hasAnyKey(properties, candidates) {
1111
+ const normalizedKeys = new Set(Object.keys(properties).map((key) => normalizeKey(key)));
1112
+ return candidates.some((candidate) => normalizedKeys.has(normalizeKey(candidate)));
1113
+ }
1114
+ function selectModalWhitelist(properties) {
1115
+ if (hasAnyKey(properties, ["nombre_del_cliente", "dpi", "capital_concedido", "kpi"])) {
1116
+ return { modalType: "cliente", whitelist: CLIENTE_MODAL_WHITELIST };
1117
+ }
1118
+ if (hasAnyKey(properties, ["nom_sector", "NOM_SECTOR", "total_clientes_sector", "capital_total", "impacto_sector"])) {
1119
+ return { modalType: "sector", whitelist: SECTOR_MODAL_WHITELIST };
1120
+ }
1121
+ return null;
1122
+ }
1123
+ function logModalWhitelistDebug(options) {
1124
+ if (process.env.NODE_ENV === "production") return;
1125
+ const { modalType, properties, entries, whitelist, fallbackToGeneric } = options;
1126
+ const matchedIds = new Set(entries.map((entry) => entry.id));
1127
+ const missingFields = (whitelist ?? []).filter((item) => !matchedIds.has(item.id)).map((item) => item.id);
1128
+ console.info("[modal-whitelist]", {
1129
+ modalType,
1130
+ keys: Object.keys(properties),
1131
+ matchedFields: entries.map((entry) => ({ id: entry.id, matchedKey: entry.matchedKey })),
1132
+ missingFields,
1133
+ fallbackToGeneric
1134
+ });
1135
+ }
918
1136
  function isPolygonType(layerType, geometryType) {
919
1137
  const candidate = (layerType ?? geometryType ?? "").toLowerCase();
920
1138
  return candidate === "polygon" || candidate === "multipolygon";
@@ -5129,4 +5347,4 @@ export {
5129
5347
  useSendMessageStream,
5130
5348
  FloatingChatBox
5131
5349
  };
5132
- //# sourceMappingURL=chunk-HCGYF65R.mjs.map
5350
+ //# sourceMappingURL=chunk-TH7D3ECH.mjs.map