pixelon 0.4.3 → 0.5.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.
package/dist/index.js CHANGED
@@ -12838,29 +12838,22 @@ const FormDrawer = ({
12838
12838
  onClose();
12839
12839
  methods.reset();
12840
12840
  }, [onClose, onBeforeClose, methods]);
12841
- const [invalidMsg, setInvalidMsg] = React.useState(null);
12842
- React.useEffect(() => {
12843
- if (!isOpen) setInvalidMsg(null);
12844
- }, [isOpen]);
12845
- React.useEffect(() => {
12846
- const sub = methods.watch(() => setInvalidMsg(null));
12847
- return () => sub.unsubscribe();
12848
- }, [methods.watch]);
12849
12841
  const handleFormSubmit = React.useCallback(
12850
12842
  async (data) => {
12851
- setInvalidMsg(null);
12852
12843
  await onSubmit(data);
12853
12844
  },
12854
12845
  [onSubmit]
12855
12846
  );
12856
12847
  const handleInvalid = React.useCallback(
12857
12848
  (formErrors) => {
12858
- const faltan = Object.keys(formErrors).map((name) => fields.find((f) => f.name === name)?.label ?? name);
12859
- setInvalidMsg(
12860
- faltan.length > 0 ? `Falta completar: ${faltan.join(", ")}.` : "Revisa los campos marcados."
12861
- );
12849
+ const primero = Object.keys(formErrors)[0];
12850
+ if (!primero) return;
12851
+ const nodo = document.querySelector(`[name="${CSS.escape(primero)}"]`);
12852
+ if (!nodo) return;
12853
+ nodo.scrollIntoView({ block: "center", behavior: "smooth" });
12854
+ window.setTimeout(() => nodo.focus({ preventScroll: true }), 300);
12862
12855
  },
12863
- [fields]
12856
+ []
12864
12857
  );
12865
12858
  const handleSubmitClick = methods.handleSubmit(handleFormSubmit, handleInvalid);
12866
12859
  const drawerTitle = title || DEFAULT_TITLES[mode];
@@ -12918,7 +12911,6 @@ const FormDrawer = ({
12918
12911
  ) }) }),
12919
12912
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${baseClass}__footer`, children: [
12920
12913
  footerExtra && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `${baseClass}__footer-extra`, children: footerExtra }),
12921
- invalidMsg && mode !== "view" && /* @__PURE__ */ jsxRuntime.jsx("p", { className: `${baseClass}__invalid`, role: "alert", children: invalidMsg }),
12922
12914
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${baseClass}__actions`, children: [
12923
12915
  /* @__PURE__ */ jsxRuntime.jsx(
12924
12916
  Button,
@@ -14133,7 +14125,7 @@ function getFormatter(key) {
14133
14125
  }
14134
14126
 
14135
14127
  const OPTIONS_LOAD_ERROR = "No se pudieron cargar las opciones. Int\xE9ntalo de nuevo.";
14136
- function unwrap$3(raw) {
14128
+ function unwrap$4(raw) {
14137
14129
  if (raw && typeof raw === "object" && "response" in raw) {
14138
14130
  return raw.response;
14139
14131
  }
@@ -14154,7 +14146,7 @@ function resolveBody(body, ctx) {
14154
14146
  }
14155
14147
  async function loadOptions(eventBus, ep, ctx) {
14156
14148
  const raw = await fetchViaEventBus(eventBus, ep.service, ep.url, ep.method, resolveBody(ep.body, ctx));
14157
- let data = unwrap$3(raw);
14149
+ let data = unwrap$4(raw);
14158
14150
  if (ep.response_path && data && typeof data === "object" && !Array.isArray(data)) {
14159
14151
  data = data[ep.response_path];
14160
14152
  }
@@ -14192,7 +14184,7 @@ const mensajeDeError = (e, respaldo) => {
14192
14184
  };
14193
14185
 
14194
14186
  const REFRESH_INTERVAL_MS = 2e4;
14195
- function unwrap$2(raw) {
14187
+ function unwrap$3(raw) {
14196
14188
  if (raw && typeof raw === "object" && "response" in raw) {
14197
14189
  return raw.response;
14198
14190
  }
@@ -14241,7 +14233,7 @@ function useReactiveCrud(config, eventBus) {
14241
14233
  filters
14242
14234
  });
14243
14235
  assertOk(raw);
14244
- const data = unwrap$2(raw);
14236
+ const data = unwrap$3(raw);
14245
14237
  let rows = [];
14246
14238
  let total = 0;
14247
14239
  if (Array.isArray(data)) {
@@ -14445,6 +14437,20 @@ const FileField = ({
14445
14437
  ] });
14446
14438
  };
14447
14439
 
14440
+ const RESPALDO = { miles: ".", decimal: "," };
14441
+ function separadoresDelLocale(locale) {
14442
+ if (!locale) return RESPALDO;
14443
+ try {
14444
+ const partes = new Intl.NumberFormat(locale).formatToParts(123456789e-2);
14445
+ const miles = partes.find((p) => p.type === "group")?.value;
14446
+ const decimal = partes.find((p) => p.type === "decimal")?.value;
14447
+ if (!miles || !decimal) return RESPALDO;
14448
+ return { miles, decimal };
14449
+ } catch {
14450
+ return RESPALDO;
14451
+ }
14452
+ }
14453
+
14448
14454
  const CRUD_TO_FORM_MOLECULE = {
14449
14455
  INPUT: "INPUT",
14450
14456
  INPUT_NUMBER: "INPUT_NUMBER",
@@ -14501,6 +14507,8 @@ function ActionFormDrawer({ action, row, idField, eventBus, onExecute, onClose }
14501
14507
  alive = false;
14502
14508
  };
14503
14509
  }, [eventBus, action.key, normalFields]);
14510
+ const { locale } = useChatConfig();
14511
+ const separadores = React.useMemo(() => separadoresDelLocale(locale), [locale]);
14504
14512
  const fields = React.useMemo(
14505
14513
  () => normalFields.map((f) => ({
14506
14514
  name: f.name,
@@ -14511,9 +14519,19 @@ function ActionFormDrawer({ action, row, idField, eventBus, onExecute, onClose }
14511
14519
  options: f.options ?? optionsByField[f.name],
14512
14520
  // SPEC-106 T8 — `uiProps` llega tal cual a la molécula, así que el desplegable dice lo
14513
14521
  // que pasó de verdad en vez del «no hay» de siempre. Sin error, se queda el de siempre.
14514
- ...optionsErrorByField[f.name] ? { uiProps: { notFoundContent: optionsErrorByField[f.name] } } : {}
14522
+ ...optionsErrorByField[f.name] ? { uiProps: { notFoundContent: optionsErrorByField[f.name] } } : {},
14523
+ // SPEC-128 — el dinero se escribe como se escribe AQUÍ.
14524
+ //
14525
+ // Los campos de moneda caían a `thousandSeparator ?? ','`, un valor por defecto en formato
14526
+ // inglés: al teclear 180000 el campo mostraba «180,000» mientras la tarjeta que recibe el
14527
+ // cliente decía «$ 180.000,00 COP». El mismo importe escrito de una manera y leído de otra.
14528
+ //
14529
+ // Se deriva del locale que el host ya declara en la config del chat, no de un valor fijo ni
14530
+ // del navegador: `navigator.language` puede ser `es-419` —español, pero con coma para los
14531
+ // miles— y entonces el resultado dependería del portátil de cada quien.
14532
+ ...f.moleculeType === "INPUT_CURRENCY" ? { uiProps: { thousandSeparator: separadores.miles, decimalSeparator: separadores.decimal } } : {}
14515
14533
  })),
14516
- [normalFields, optionsByField, optionsErrorByField]
14534
+ [normalFields, optionsByField, optionsErrorByField, separadores]
14517
14535
  );
14518
14536
  const validationSchema = React.useMemo(() => buildCrudYupSchema(normalFields), [normalFields]);
14519
14537
  const uploadOne = async (f, file, idx) => {
@@ -15172,6 +15190,95 @@ const FileViewer = ({
15172
15190
  ] });
15173
15191
  };
15174
15192
 
15193
+ function unwrap$2(raw) {
15194
+ if (raw && typeof raw === "object" && "response" in raw) {
15195
+ return raw.response;
15196
+ }
15197
+ return raw;
15198
+ }
15199
+ function hora(iso) {
15200
+ if (!iso) return "";
15201
+ const d = new Date(iso);
15202
+ if (Number.isNaN(d.getTime())) return "";
15203
+ return d.toLocaleString(void 0, { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" });
15204
+ }
15205
+ function TranscriptSection({ transcript, values, eventBus }) {
15206
+ const chatId = values[transcript.chatIdField];
15207
+ const id = chatId == null || chatId === "" ? "" : String(chatId);
15208
+ const [datos, setDatos] = React.useState(null);
15209
+ const [cargando, setCargando] = React.useState(true);
15210
+ const [fallo, setFallo] = React.useState(false);
15211
+ React.useEffect(() => {
15212
+ if (!eventBus || !id) {
15213
+ setCargando(false);
15214
+ return;
15215
+ }
15216
+ let vivo = true;
15217
+ setCargando(true);
15218
+ setFallo(false);
15219
+ void (async () => {
15220
+ try {
15221
+ const raw = await fetchViaEventBus(
15222
+ eventBus,
15223
+ transcript.get.service,
15224
+ transcript.get.url,
15225
+ transcript.get.method ?? "POST",
15226
+ { [transcript.param ?? "chat_id"]: id }
15227
+ );
15228
+ if (vivo) {
15229
+ setDatos(unwrap$2(raw) ?? {});
15230
+ setCargando(false);
15231
+ }
15232
+ } catch {
15233
+ if (vivo) {
15234
+ setFallo(true);
15235
+ setCargando(false);
15236
+ }
15237
+ }
15238
+ })();
15239
+ return () => {
15240
+ vivo = false;
15241
+ };
15242
+ }, [eventBus, id, transcript]);
15243
+ if (!id) return null;
15244
+ const lineas = datos?.lines ?? [];
15245
+ const dijoAlgo = (datos?.from_user ?? 0) > 0;
15246
+ const nombres = {
15247
+ user: transcript.labels?.user ?? "Cliente",
15248
+ assistant: transcript.labels?.assistant ?? "Asistente"
15249
+ };
15250
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-crud-transcript", children: [
15251
+ /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "px-chat-crud-transcript__title", children: transcript.title ?? "Conversaci\xF3n" }),
15252
+ cargando && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-transcript__note", children: "Cargando\u2026" }),
15253
+ !cargando && fallo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-transcript__note", children: "No se pudo cargar la conversaci\xF3n." }),
15254
+ !cargando && !fallo && !dijoAlgo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-transcript__note", children: transcript.silentText ?? "Todav\xEDa no ha escrito nada." }),
15255
+ !cargando && !fallo && lineas.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "px-chat-crud-transcript__lines", children: lineas.map((l, i) => /* @__PURE__ */ jsxRuntime.jsxs(
15256
+ "li",
15257
+ {
15258
+ className: [
15259
+ "px-chat-crud-transcript__line",
15260
+ l.rol === "user" ? "is-user" : "is-assistant"
15261
+ ].join(" "),
15262
+ children: [
15263
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-chat-crud-transcript__who", children: [
15264
+ l.rol === "user" ? nombres.user : nombres.assistant,
15265
+ hora(l.created_date) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-crud-transcript__when", children: hora(l.created_date) })
15266
+ ] }),
15267
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-crud-transcript__text", children: l.text })
15268
+ ]
15269
+ },
15270
+ `${i}-${l.created_date ?? ""}`
15271
+ )) }),
15272
+ !cargando && !fallo && (datos?.total ?? 0) > lineas.length && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-crud-transcript__note", children: [
15273
+ "Se muestran los \xFAltimos ",
15274
+ lineas.length,
15275
+ " de ",
15276
+ datos?.total,
15277
+ " mensajes."
15278
+ ] })
15279
+ ] });
15280
+ }
15281
+
15175
15282
  function unwrap$1(raw) {
15176
15283
  if (raw && typeof raw === "object" && "response" in raw) {
15177
15284
  return raw.response;
@@ -15300,6 +15407,7 @@ function DetailDrawer({ row, config, eventBus, onClose, loadedOptions }) {
15300
15407
  ] })
15301
15408
  ] }, f.name);
15302
15409
  }) }),
15410
+ config.transcript && /* @__PURE__ */ jsxRuntime.jsx(TranscriptSection, { transcript: config.transcript, values, eventBus }),
15303
15411
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-reactive-crud-detail__photos", children: [
15304
15412
  /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "px-chat-reactive-crud-detail__photos-title", children: "Fotos y documentos" }),
15305
15413
  loading ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-reactive-crud-detail__empty", children: "Cargando\u2026" }) : files.length ? /* @__PURE__ */ jsxRuntime.jsx(FileViewer, { files }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-reactive-crud-detail__empty", children: "Este servicio no tiene archivos." })
@@ -16006,6 +16114,10 @@ function matchesVisibleWhen(a, row) {
16006
16114
  if (!a.visibleWhen) return true;
16007
16115
  return cumplenTodas(a.visibleWhen, row);
16008
16116
  }
16117
+ function laQueTocaAhora(actions, row) {
16118
+ const candidatas = actions.filter((a) => a.ahoraToca && cumplenTodas(a.ahoraToca, row));
16119
+ return candidatas.length === 1 ? candidatas[0] : void 0;
16120
+ }
16009
16121
  function condicionesDeshabilitado(a) {
16010
16122
  if (!a.disabledWhen) return [];
16011
16123
  return Array.isArray(a.disabledWhen) ? a.disabledWhen : [a.disabledWhen];
@@ -16326,7 +16438,7 @@ function DeadlineCountdown({ deadline, label, expiredLabel }) {
16326
16438
  }
16327
16439
 
16328
16440
  function ReactiveCrudItemChat({ component, eventBus }) {
16329
- const { resolveModuleConfig } = useChatConfig();
16441
+ const { resolveModuleConfig, resolveMomento } = useChatConfig();
16330
16442
  const props = component.props ?? {};
16331
16443
  const top = component;
16332
16444
  const pick = (key) => props[key] !== void 0 ? props[key] : top[key];
@@ -16334,7 +16446,11 @@ function ReactiveCrudItemChat({ component, eventBus }) {
16334
16446
  const recordId = pick("record_id") ?? pick("recordId") ?? pick("id") ?? pick("service_id");
16335
16447
  const recordLabel = pick("record_label") ?? pick("label");
16336
16448
  const allowedRaw = pick("actions");
16337
- const allowed = Array.isArray(allowedRaw) && allowedRaw.length > 0 ? allowedRaw : void 0;
16449
+ const allowedLegacy = Array.isArray(allowedRaw) && allowedRaw.length > 0 ? allowedRaw : void 0;
16450
+ const momento = pick("momento");
16451
+ const delMomento = momento && resolveMomento ? resolveMomento(momento) : void 0;
16452
+ const allowed = delMomento ?? allowedLegacy;
16453
+ const sinAcciones = delMomento?.length === 0;
16338
16454
  const config = typeof moduleKey === "string" && resolveModuleConfig ? resolveModuleConfig(moduleKey) : void 0;
16339
16455
  if (!config || recordId == null || recordId === "") return null;
16340
16456
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -16344,11 +16460,12 @@ function ReactiveCrudItemChat({ component, eventBus }) {
16344
16460
  recordId: String(recordId),
16345
16461
  recordLabel,
16346
16462
  allowed: Array.isArray(allowed) ? allowed.map(String) : void 0,
16463
+ sinAcciones,
16347
16464
  eventBus
16348
16465
  }
16349
16466
  );
16350
16467
  }
16351
- function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus }) {
16468
+ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, sinAcciones, eventBus }) {
16352
16469
  const { chatIsForeign } = useChatConfig();
16353
16470
  const crud = useReactiveCrud(config, eventBus);
16354
16471
  const [activeAction, setActiveAction] = React.useState(null);
@@ -16397,9 +16514,26 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
16397
16514
  }, [recordId]);
16398
16515
  const gastada = !esUltima;
16399
16516
  const actions = React.useMemo(() => {
16400
- if (!row || gastada) return [];
16401
- return (config.rowActions ?? []).filter((a) => !allowed || allowed.includes(a.key)).filter((a) => matchesVisibleWhen(a, row));
16517
+ if (!row) return [];
16518
+ if (gastada) {
16519
+ const hechas = (config.rowActions ?? []).filter((a) => !allowed || allowed.includes(a.key)).filter((a) => matchesDoneWhen(a, row));
16520
+ const vistas = /* @__PURE__ */ new Set();
16521
+ return hechas.filter((a) => {
16522
+ const linea = a.doneLabel ?? a.label;
16523
+ if (vistas.has(linea)) return false;
16524
+ vistas.add(linea);
16525
+ return true;
16526
+ });
16527
+ }
16528
+ const visibles = (config.rowActions ?? []).filter((a) => !allowed || allowed.includes(a.key)).filter((a) => matchesVisibleWhen(a, row));
16529
+ const toca = laQueTocaAhora(visibles, row);
16530
+ if (!toca) return visibles;
16531
+ return [toca, ...visibles.filter((a) => a.key !== toca.key)];
16402
16532
  }, [config.rowActions, row, allowed, gastada]);
16533
+ const claveQueToca = React.useMemo(
16534
+ () => row && !gastada ? laQueTocaAhora(actions, row)?.key : void 0,
16535
+ [actions, row, gastada]
16536
+ );
16403
16537
  const title = recordLabel ?? config.title ?? "Servicio";
16404
16538
  return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-crud-item", ref: raiz, "data-panel-record": recordId, children: [
16405
16539
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-item__header", children: title }),
@@ -16410,7 +16544,7 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
16410
16544
  crud.loading && !row && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-item__hint", children: "Cargando\u2026" }),
16411
16545
  !crud.loading && !row && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-item__hint", children: "No se encontr\xF3 el servicio." }),
16412
16546
  gastada && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-item__hint", children: "Este paso ya se gestion\xF3. Contin\xFAa en el mensaje m\xE1s reciente." }),
16413
- row && config.deadline && typeof row[config.deadline.field] === "string" && /* @__PURE__ */ jsxRuntime.jsx(
16547
+ row && !gastada && config.deadline && typeof row[config.deadline.field] === "string" && /* @__PURE__ */ jsxRuntime.jsx(
16414
16548
  DeadlineCountdown,
16415
16549
  {
16416
16550
  deadline: row[config.deadline.field],
@@ -16421,7 +16555,7 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
16421
16555
  row && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-crud-item__actions", children: [
16422
16556
  config.detail && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "px-chat-crud-item__action", onClick: () => setDetailRow(row), children: "Ver" }),
16423
16557
  actions.map((a) => {
16424
- const disabled = Boolean(chatIsForeign) || matchesDisabledWhen(a, row);
16558
+ const disabled = gastada || Boolean(chatIsForeign) || matchesDisabledWhen(a, row);
16425
16559
  const motivo = chatIsForeign ? "Esta conversaci\xF3n es de otra persona" : disabledReasonFor(a, row);
16426
16560
  const done = matchesDoneWhen(a, row);
16427
16561
  return /* @__PURE__ */ jsxRuntime.jsxs(
@@ -16431,13 +16565,18 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
16431
16565
  className: [
16432
16566
  "px-chat-crud-item__action",
16433
16567
  a.intent === "danger" ? "is-danger" : "",
16434
- disabled && motivo ? "is-con-motivo" : ""
16568
+ disabled && motivo ? "is-con-motivo" : "",
16569
+ // SPEC-129 T6 — lo hecho se pinta como un acta, no como un botón apagado.
16570
+ gastada ? "is-hecho" : "",
16571
+ // SPEC-127 T4 — señalada, pero solo si de verdad se puede pulsar: destacar una
16572
+ // acción apagada sería dirigir a alguien a una puerta cerrada.
16573
+ a.key === claveQueToca && !disabled ? "is-ahora" : ""
16435
16574
  ].filter(Boolean).join(" "),
16436
16575
  disabled,
16437
16576
  onClick: () => a.form ? setActiveAction({ action: a, row }) : crud.runEndpoints(a.endpoints ?? [a.endpoint], { ...row, id: row[config.idField] }),
16438
16577
  children: [
16439
16578
  /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-chat-crud-item__action-texts", children: [
16440
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: a.label }),
16579
+ /* @__PURE__ */ jsxRuntime.jsx("span", { children: gastada && a.doneLabel ? a.doneLabel : a.label }),
16441
16580
  disabled && motivo && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-crud-item__action-reason", children: motivo })
16442
16581
  ] }),
16443
16582
  done && /* @__PURE__ */ jsxRuntime.jsx(Icon$1, { type: "check-circle", width: 18, height: 18, className: "px-chat-crud-item__done", "aria-label": "Hecho" })
@@ -16446,7 +16585,7 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
16446
16585
  a.key
16447
16586
  );
16448
16587
  }),
16449
- actions.length === 0 && !config.detail && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-item__hint", children: "Sin acciones disponibles." })
16588
+ actions.length === 0 && !config.detail && !sinAcciones && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-item__hint", children: "Sin acciones disponibles." })
16450
16589
  ] }),
16451
16590
  activeAction && /* @__PURE__ */ jsxRuntime.jsx(
16452
16591
  ActionFormDrawer,
@@ -16666,7 +16805,7 @@ const ServicesMap = ({ config, eventBus, apiKey, filter, fill }) => {
16666
16805
  ),
16667
16806
  simulated > 0 && ` \xB7 ${config.live?.labels?.simulatedText ?? "incluye posiciones simuladas"}`
16668
16807
  ] }),
16669
- missing > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: `${CLASS$6}__note`, children: (labels.missingText ?? "{n} sin ubicaci\xF3n registrada").replace("{n}", String(missing)) }),
16808
+ missing > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: `${CLASS$6}__note`, children: ((missing === 1 ? labels.missingTextOne : void 0) ?? labels.missingText ?? "{n} sin ubicaci\xF3n registrada").replace("{n}", String(missing)) }),
16670
16809
  outside > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: `${CLASS$6}__note`, children: (labels.outsideText ?? "{n} fuera de la zona (aleja el mapa para verlos)").replace(
16671
16810
  "{n}",
16672
16811
  String(outside)