zenit-sdk 0.1.9 → 0.2.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.
package/dist/index.js CHANGED
@@ -2010,49 +2010,146 @@ function useGeolocation(options) {
2010
2010
  var import_leaflet2 = __toESM(require("leaflet"));
2011
2011
 
2012
2012
  // src/config/modalWhitelist.ts
2013
- var SECTOR_MODAL_WHITELIST = [
2014
- { key: "Sector", label: "Sector" },
2015
- { key: "Promotor", label: "Promotor" },
2016
- { key: "Capital Total", label: "Capital Total" },
2017
- { key: "Total Capital Mora", label: "Capital en Mora" },
2018
- { key: "Tendencia Mora", label: "Tendencia de Mora", hint: "trend_icon" },
2019
- { key: "Tendencia Capital", label: "Tendencia de Capital", hint: "trend_icon" },
2020
- { key: "Tendencia Castigos", label: "Tendencia de Castigos", hint: "trend_icon" },
2021
- { key: "Impacto Sector", label: "Impacto del Sector" },
2022
- { key: "Total Clientes Sector", label: "Total de Clientes" },
2023
- { key: "Total Clientes Sanos", label: "Clientes Sanos" },
2024
- { key: "Total Clientes Morosos", label: "Clientes en Mora" },
2025
- { key: "Total Clientes Castigados", label: "Clientes Castigados" },
2026
- { key: "Total Clientes Nuevos", label: "Clientes Nuevos" },
2027
- { key: "Total Clientes Salidos", label: "Clientes Salidos" },
2028
- { key: "Insights", label: "An\xE1lisis IA", hint: "collapsible" },
2029
- { key: "Recomendaciones", label: "Recomendaciones IA", hint: "collapsible" }
2030
- ];
2013
+ function normalizeKey(value) {
2014
+ return value.normalize("NFD").replace(/\p{Diacritic}/gu, "").replace(/[_\s-]+/g, "").toLowerCase().trim();
2015
+ }
2031
2016
  var CLIENTE_MODAL_WHITELIST = [
2032
- { key: "nombre del cliente", label: "Nombre del Cliente" },
2033
- { key: "dpi", label: "DPI" },
2034
- { key: "kpi", label: "Estado", hint: "kpi_badge" },
2035
- { key: "tel principal", label: "Tel\xE9fono", hint: "phone_link" },
2036
- { key: "capital concedido", label: "Capital Concedido" },
2037
- { key: "mora", label: "Monto en Mora", hint: "mora_alert" },
2038
- { key: "etapa", label: "Etapa del Cr\xE9dito" },
2039
- { key: "prestamo", label: "No. de Pr\xE9stamo" },
2040
- { key: "sucursal", label: "Sucursal", aliases: ["nombre sucursal"] }
2017
+ {
2018
+ id: "nombre_cliente",
2019
+ label: "Nombre del Cliente",
2020
+ aliases: ["nombre_del_cliente", "nombre cliente", "nombre_del_cliente ", "NOMBRE_CLIENTE"]
2021
+ },
2022
+ {
2023
+ id: "dpi",
2024
+ label: "DPI",
2025
+ aliases: ["dpi", "DPI"]
2026
+ },
2027
+ {
2028
+ id: "kpi",
2029
+ label: "Estado",
2030
+ aliases: ["kpi", "KPI"],
2031
+ hint: "kpi_badge"
2032
+ },
2033
+ {
2034
+ id: "tel_principal",
2035
+ label: "Tel\xE9fono",
2036
+ aliases: ["tel_principal", "tel principal", "telefono", "telefono_principal", "TEL_PRINCIPAL"],
2037
+ hint: "phone_link"
2038
+ },
2039
+ {
2040
+ id: "capital_concedido",
2041
+ label: "Capital Concedido",
2042
+ aliases: ["capital_concedido", "capital concedido", "CAPITAL_CONCEDIDO"]
2043
+ },
2044
+ {
2045
+ id: "mora",
2046
+ label: "Monto en Mora",
2047
+ aliases: ["mora", "MORA"],
2048
+ hint: "mora_alert"
2049
+ },
2050
+ {
2051
+ id: "etapa",
2052
+ label: "Etapa del Cr\xE9dito",
2053
+ aliases: ["etapa", "ETAPA"]
2054
+ },
2055
+ {
2056
+ id: "prestamo",
2057
+ label: "No. de Pr\xE9stamo",
2058
+ aliases: ["prestamo", "prestamo_id", "no_prestamo", "numero_prestamo", "PRESTAMO"]
2059
+ },
2060
+ {
2061
+ id: "sucursal",
2062
+ label: "Sucursal",
2063
+ aliases: ["sucursal", "nombre_sucursal", "nombre sucursal", "SUCURSAL"]
2064
+ }
2065
+ ];
2066
+ var SECTOR_MODAL_WHITELIST = [
2067
+ { id: "sector", label: "Sector", aliases: ["nom_sector", "NOM_SECTOR", "sector", "SECTOR"] },
2068
+ { id: "promotor", label: "Promotor", aliases: ["promotor", "PROMOTOR"] },
2069
+ { id: "capital_total", label: "Capital Total", aliases: ["capital_total", "capital total", "CAPITAL_TOTAL"] },
2070
+ {
2071
+ id: "total_capital_mora",
2072
+ label: "Total Capital Mora",
2073
+ aliases: ["total_capital_mora", "total capital mora", "TOTAL_CAPITAL_MORA"]
2074
+ },
2075
+ {
2076
+ id: "tendencia_mora",
2077
+ label: "Tendencia Mora",
2078
+ aliases: ["tendencia_mora", "tendencia mora", "TENDENCIA_MORA"],
2079
+ hint: "trend_icon"
2080
+ },
2081
+ {
2082
+ id: "tendencia_capital",
2083
+ label: "Tendencia Capital",
2084
+ aliases: ["tendencia_capital", "tendencia capital", "TENDENCIA_CAPITAL"],
2085
+ hint: "trend_icon"
2086
+ },
2087
+ {
2088
+ id: "tendencia_castigos",
2089
+ label: "Tendencia Castigos",
2090
+ aliases: ["tendencia_castigos", "tendencia castigos", "TENDENCIA_CASTIGOS"],
2091
+ hint: "trend_icon"
2092
+ },
2093
+ {
2094
+ id: "impacto_sector",
2095
+ label: "Impacto Sector",
2096
+ aliases: ["impacto_sector", "impacto sector", "IMPACTO_SECTOR"]
2097
+ },
2098
+ {
2099
+ id: "total_clientes_sector",
2100
+ label: "Total Clientes Sector",
2101
+ aliases: ["total_clientes_sector", "total clientes sector", "TOTAL_CLIENTES_SECTOR"]
2102
+ },
2103
+ {
2104
+ id: "total_clientes_sanos",
2105
+ label: "Total Clientes Sanos",
2106
+ aliases: ["total_clientes_sanos", "total clientes sanos", "TOTAL_CLIENTES_SANOS"]
2107
+ },
2108
+ {
2109
+ id: "total_clientes_morosos",
2110
+ label: "Total Clientes Morosos",
2111
+ aliases: ["total_clientes_morosos", "total clientes morosos", "TOTAL_CLIENTES_MOROSOS"]
2112
+ },
2113
+ {
2114
+ id: "total_clientes_castigados",
2115
+ label: "Total Clientes Castigados",
2116
+ aliases: ["total_clientes_castigados", "total clientes castigados", "TOTAL_CLIENTES_CASTIGADOS"]
2117
+ },
2118
+ {
2119
+ id: "total_clientes_nuevos",
2120
+ label: "Total Clientes Nuevos",
2121
+ aliases: ["total_clientes_nuevos", "total clientes nuevos", "TOTAL_CLIENTES_NUEVOS"]
2122
+ },
2123
+ {
2124
+ id: "total_clientes_salidos",
2125
+ label: "Total Clientes Salidos",
2126
+ aliases: ["total_clientes_salidos", "total clientes salidos", "TOTAL_CLIENTES_SALIDOS"]
2127
+ },
2128
+ { id: "insights", label: "Insights", aliases: ["insights", "INSIGHTS"], hint: "collapsible" },
2129
+ {
2130
+ id: "recomendaciones",
2131
+ label: "Recomendaciones",
2132
+ aliases: ["recomendaciones", "RECOMENDACIONES"],
2133
+ hint: "collapsible"
2134
+ }
2041
2135
  ];
2042
2136
  function applyModalWhitelist(rawData, whitelist) {
2043
- const keys = Object.keys(rawData ?? {});
2044
- return whitelist.map(({ key, label, hint, aliases = [] }) => {
2045
- const keysToTry = [key, ...aliases];
2046
- let value = void 0;
2047
- for (const k of keysToTry) {
2048
- const match = keys.find((rawKey) => rawKey.toLowerCase() === k.toLowerCase());
2049
- if (match !== void 0 && rawData[match] !== null && rawData[match] !== void 0) {
2050
- value = rawData[match];
2051
- break;
2052
- }
2137
+ const keyByNormalized = /* @__PURE__ */ new Map();
2138
+ Object.keys(rawData ?? {}).forEach((rawKey) => {
2139
+ const normalized = normalizeKey(rawKey);
2140
+ if (!normalized || keyByNormalized.has(normalized)) return;
2141
+ keyByNormalized.set(normalized, rawKey);
2142
+ });
2143
+ return whitelist.map(({ id, label, hint, aliases }) => {
2144
+ const candidates = [...aliases, id];
2145
+ for (const candidate of candidates) {
2146
+ const matchedKey = keyByNormalized.get(normalizeKey(candidate));
2147
+ if (!matchedKey) continue;
2148
+ const value = rawData[matchedKey];
2149
+ if (value === null || value === void 0) continue;
2150
+ return { id, label, value, hint: hint ?? null, matchedKey };
2053
2151
  }
2054
- if (value === void 0) return null;
2055
- return { label, value, hint: hint ?? null };
2152
+ return null;
2056
2153
  }).filter((entry) => Boolean(entry));
2057
2154
  }
2058
2155
 
@@ -2293,10 +2390,6 @@ function shouldIncludePopupEntry(key, value) {
2293
2390
  return true;
2294
2391
  }
2295
2392
  function createPopupContent(properties) {
2296
- const whitelistedRows = buildWhitelistedRows(properties);
2297
- if (whitelistedRows) {
2298
- return whitelistedRows;
2299
- }
2300
2393
  const header = findHeaderProperties(properties);
2301
2394
  const headerText = header.title?.value ?? extractPopupHeader(properties);
2302
2395
  const usedKeys = new Set([header.title?.key, header.badge?.key, header.description?.key].filter(Boolean));
@@ -2320,6 +2413,10 @@ function createPopupContent(properties) {
2320
2413
  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(
2321
2414
  header.description.value
2322
2415
  )}</div>` : "";
2416
+ const whitelistedRows = buildWhitelistedRows(properties, { colorBar, headerHtml, descriptionHtml });
2417
+ if (whitelistedRows) {
2418
+ return whitelistedRows;
2419
+ }
2323
2420
  const rowsHtml = entries.map(([key, value]) => {
2324
2421
  const label = escapeHtml(formatLabel(key));
2325
2422
  const normalizedKey = key.trim().toLowerCase();
@@ -2336,13 +2433,37 @@ function createPopupContent(properties) {
2336
2433
  }).join("");
2337
2434
  return `<div>${colorBar}${headerHtml}${descriptionHtml}${rowsHtml}</div>`;
2338
2435
  }
2339
- function buildWhitelistedRows(properties) {
2340
- const whitelist = selectModalWhitelist(properties);
2341
- if (!whitelist) return null;
2436
+ function buildWhitelistedRows(properties, headerSections) {
2437
+ const selection = selectModalWhitelist(properties);
2438
+ if (!selection) {
2439
+ logModalWhitelistDebug({
2440
+ modalType: "generic",
2441
+ properties,
2442
+ entries: [],
2443
+ whitelist: null,
2444
+ fallbackToGeneric: true
2445
+ });
2446
+ return null;
2447
+ }
2448
+ const { whitelist, modalType } = selection;
2342
2449
  const entries = applyModalWhitelist(properties, whitelist);
2343
2450
  if (entries.length === 0) {
2344
- return '<div style="padding:8px 0; color:#64748b; text-align:center;">Sin datos disponibles</div>';
2451
+ logModalWhitelistDebug({
2452
+ modalType,
2453
+ properties,
2454
+ entries,
2455
+ whitelist,
2456
+ fallbackToGeneric: true
2457
+ });
2458
+ return null;
2345
2459
  }
2460
+ logModalWhitelistDebug({
2461
+ modalType,
2462
+ properties,
2463
+ entries,
2464
+ whitelist,
2465
+ fallbackToGeneric: false
2466
+ });
2346
2467
  const rowsHtml = entries.map(({ label, value }) => {
2347
2468
  const valueHtml = renderPopupValue(value);
2348
2469
  return `
@@ -2352,20 +2473,33 @@ function buildWhitelistedRows(properties) {
2352
2473
  </div>
2353
2474
  `;
2354
2475
  }).join("");
2355
- return `<div>${rowsHtml}</div>`;
2476
+ return `<div>${headerSections.colorBar}${headerSections.headerHtml}${headerSections.descriptionHtml}${rowsHtml}</div>`;
2356
2477
  }
2357
- function countWhitelistMatches(properties, whitelist) {
2358
- const keys = Object.keys(properties).map((key) => key.toLowerCase());
2359
- return whitelist.reduce((count, item) => {
2360
- const candidates = [item.key, ...item.aliases ?? []].map((candidate) => candidate.toLowerCase());
2361
- return candidates.some((candidate) => keys.includes(candidate)) ? count + 1 : count;
2362
- }, 0);
2478
+ function hasAnyKey(properties, candidates) {
2479
+ const normalizedKeys = new Set(Object.keys(properties).map((key) => normalizeKey(key)));
2480
+ return candidates.some((candidate) => normalizedKeys.has(normalizeKey(candidate)));
2363
2481
  }
2364
2482
  function selectModalWhitelist(properties) {
2365
- const sectorMatches = countWhitelistMatches(properties, SECTOR_MODAL_WHITELIST);
2366
- const clienteMatches = countWhitelistMatches(properties, CLIENTE_MODAL_WHITELIST);
2367
- if (sectorMatches === 0 && clienteMatches === 0) return null;
2368
- return sectorMatches >= clienteMatches ? SECTOR_MODAL_WHITELIST : CLIENTE_MODAL_WHITELIST;
2483
+ if (hasAnyKey(properties, ["nombre_del_cliente", "dpi", "capital_concedido", "kpi"])) {
2484
+ return { modalType: "cliente", whitelist: CLIENTE_MODAL_WHITELIST };
2485
+ }
2486
+ if (hasAnyKey(properties, ["nom_sector", "NOM_SECTOR", "total_clientes_sector", "capital_total", "impacto_sector"])) {
2487
+ return { modalType: "sector", whitelist: SECTOR_MODAL_WHITELIST };
2488
+ }
2489
+ return null;
2490
+ }
2491
+ function logModalWhitelistDebug(options) {
2492
+ if (process.env.NODE_ENV === "production") return;
2493
+ const { modalType, properties, entries, whitelist, fallbackToGeneric } = options;
2494
+ const matchedIds = new Set(entries.map((entry) => entry.id));
2495
+ const missingFields = (whitelist ?? []).filter((item) => !matchedIds.has(item.id)).map((item) => item.id);
2496
+ console.info("[modal-whitelist]", {
2497
+ modalType,
2498
+ keys: Object.keys(properties),
2499
+ matchedFields: entries.map((entry) => ({ id: entry.id, matchedKey: entry.matchedKey })),
2500
+ missingFields,
2501
+ fallbackToGeneric
2502
+ });
2369
2503
  }
2370
2504
  function isPolygonType(layerType, geometryType) {
2371
2505
  const candidate = (layerType ?? geometryType ?? "").toLowerCase();
@@ -3224,7 +3358,7 @@ var ZenitMap = (0, import_react5.forwardRef)(({
3224
3358
  );
3225
3359
  if (layerStates && onLayerStateChange) {
3226
3360
  const next = effectiveStates.map(
3227
- (state) => state.layerId === layerId ? {
3361
+ (state) => isLayerIdMatch(state.layerId, layerId) ? {
3228
3362
  ...state,
3229
3363
  baseOpacity,
3230
3364
  opacity: effectiveOpacity,
@@ -3235,11 +3369,11 @@ var ZenitMap = (0, import_react5.forwardRef)(({
3235
3369
  return;
3236
3370
  }
3237
3371
  setBaseStates(
3238
- (prev) => prev.map((state) => state.layerId === layerId ? { ...state, baseOpacity } : state)
3372
+ (prev) => prev.map((state) => isLayerIdMatch(state.layerId, layerId) ? { ...state, baseOpacity } : state)
3239
3373
  );
3240
3374
  setUiOverrides((prev) => {
3241
- const existing = prev.find((entry) => entry.layerId === layerId);
3242
- const filtered = prev.filter((entry) => entry.layerId !== layerId);
3375
+ const existing = prev.find((entry) => isLayerIdMatch(entry.layerId, layerId));
3376
+ const filtered = prev.filter((entry) => !isLayerIdMatch(entry.layerId, layerId));
3243
3377
  if (existing && existing.overrideVisible !== void 0) {
3244
3378
  return [
3245
3379
  ...filtered,
@@ -3281,7 +3415,7 @@ var ZenitMap = (0, import_react5.forwardRef)(({
3281
3415
  const override = layerGeojsonOverrides[layerKey];
3282
3416
  return {
3283
3417
  ...layer,
3284
- effective: effectiveStates.find((state) => state.layerId === layer.mapLayer.layerId),
3418
+ effective: effectiveStates.find((state) => isLayerIdMatch(state.layerId, layer.mapLayer.layerId)),
3285
3419
  data: override ?? layerGeojson?.[layer.mapLayer.layerId] ?? layerGeojson?.[layerKey] ?? null
3286
3420
  };
3287
3421
  });