pixelon 0.4.3 → 0.5.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/components/molecules/chat/StructuredContent/components/LocationField/usePlaces.d.ts +11 -0
- package/dist/components/molecules/chat/StructuredContent/components/ReactiveCrud/ReactiveCrud.d.ts +1 -0
- package/dist/components/molecules/chat/StructuredContent/components/ReactiveCrud/TranscriptSection.d.ts +10 -0
- package/dist/components/molecules/chat/StructuredContent/components/ReactiveCrud/types.d.ts +40 -1
- package/dist/components/molecules/chat/StructuredContent/components/ServicesMap/types.d.ts +9 -0
- package/dist/components/molecules/chat/StructuredContent/components/index.d.ts +0 -1
- package/dist/components/organisms/chat/Chat/hooks/useAutoScroll.d.ts +8 -1
- package/dist/components/templates/lumi/Crud/helpers/confirmSummary.d.ts +13 -0
- package/dist/components/templates/lumi/Crud/types.d.ts +6 -0
- package/dist/core/chat/ChatConfigContext.d.ts +25 -0
- package/dist/core/i18n/separadores.d.ts +12 -0
- package/dist/index.esm.js +293 -44
- package/dist/index.js +293 -44
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
- package/src/styles/index.scss +1 -0
package/dist/index.js
CHANGED
|
@@ -10945,6 +10945,7 @@ const Drawer = ({
|
|
|
10945
10945
|
"data-testid": dataTestId,
|
|
10946
10946
|
scrollIndicatorOffset = 1
|
|
10947
10947
|
}) => {
|
|
10948
|
+
const idTitulo = React.useId();
|
|
10948
10949
|
const [isMobile, setIsMobile] = React.useState(false);
|
|
10949
10950
|
const contentRef = React.useRef(null);
|
|
10950
10951
|
const [showScrollIndicator, setShowScrollIndicator] = React.useState(false);
|
|
@@ -11068,14 +11069,14 @@ const Drawer = ({
|
|
|
11068
11069
|
style: getDrawerStyles(),
|
|
11069
11070
|
role: "dialog",
|
|
11070
11071
|
"aria-modal": "true",
|
|
11071
|
-
"aria-labelledby": title ?
|
|
11072
|
+
"aria-labelledby": title ? idTitulo : void 0,
|
|
11072
11073
|
"data-testid": dataTestId,
|
|
11073
11074
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${COMPONENT_PREFIX}drawer__viewport`, children: [
|
|
11074
11075
|
(title || showCloseButton || headerExtra) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${COMPONENT_PREFIX}drawer__header`, children: [
|
|
11075
11076
|
title && /* @__PURE__ */ jsxRuntime.jsx(
|
|
11076
11077
|
"h2",
|
|
11077
11078
|
{
|
|
11078
|
-
id:
|
|
11079
|
+
id: idTitulo,
|
|
11079
11080
|
className: `${COMPONENT_PREFIX}drawer__title`,
|
|
11080
11081
|
children: title
|
|
11081
11082
|
}
|
|
@@ -12838,29 +12839,22 @@ const FormDrawer = ({
|
|
|
12838
12839
|
onClose();
|
|
12839
12840
|
methods.reset();
|
|
12840
12841
|
}, [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
12842
|
const handleFormSubmit = React.useCallback(
|
|
12850
12843
|
async (data) => {
|
|
12851
|
-
setInvalidMsg(null);
|
|
12852
12844
|
await onSubmit(data);
|
|
12853
12845
|
},
|
|
12854
12846
|
[onSubmit]
|
|
12855
12847
|
);
|
|
12856
12848
|
const handleInvalid = React.useCallback(
|
|
12857
12849
|
(formErrors) => {
|
|
12858
|
-
const
|
|
12859
|
-
|
|
12860
|
-
|
|
12861
|
-
);
|
|
12850
|
+
const primero = Object.keys(formErrors)[0];
|
|
12851
|
+
if (!primero) return;
|
|
12852
|
+
const nodo = document.querySelector(`[name="${CSS.escape(primero)}"]`);
|
|
12853
|
+
if (!nodo) return;
|
|
12854
|
+
nodo.scrollIntoView({ block: "center", behavior: "smooth" });
|
|
12855
|
+
window.setTimeout(() => nodo.focus({ preventScroll: true }), 300);
|
|
12862
12856
|
},
|
|
12863
|
-
[
|
|
12857
|
+
[]
|
|
12864
12858
|
);
|
|
12865
12859
|
const handleSubmitClick = methods.handleSubmit(handleFormSubmit, handleInvalid);
|
|
12866
12860
|
const drawerTitle = title || DEFAULT_TITLES[mode];
|
|
@@ -12918,7 +12912,6 @@ const FormDrawer = ({
|
|
|
12918
12912
|
) }) }),
|
|
12919
12913
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${baseClass}__footer`, children: [
|
|
12920
12914
|
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
12915
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${baseClass}__actions`, children: [
|
|
12923
12916
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
12924
12917
|
Button,
|
|
@@ -13196,7 +13189,9 @@ function mapFieldsToFormFields(fields, mode) {
|
|
|
13196
13189
|
readOnly: field.readOnly,
|
|
13197
13190
|
placeholder: field.placeholder,
|
|
13198
13191
|
uiProps: field.uiProps,
|
|
13199
|
-
transformOnSubmit: field.parseValue
|
|
13192
|
+
transformOnSubmit: field.parseValue,
|
|
13193
|
+
gridSpan: field.gridSpan
|
|
13194
|
+
// SPEC-131 T7
|
|
13200
13195
|
}));
|
|
13201
13196
|
}
|
|
13202
13197
|
|
|
@@ -13376,6 +13371,47 @@ function calculateTotalPages(totalRecords, limit) {
|
|
|
13376
13371
|
return Math.ceil(totalRecords / limit);
|
|
13377
13372
|
}
|
|
13378
13373
|
|
|
13374
|
+
function etiquetaDeOpcion(valor, uiProps) {
|
|
13375
|
+
const opciones = uiProps?.options;
|
|
13376
|
+
if (!Array.isArray(opciones)) return null;
|
|
13377
|
+
const encontrada = opciones.find((o) => o && String(o.value) === String(valor));
|
|
13378
|
+
return encontrada?.label != null ? String(encontrada.label) : null;
|
|
13379
|
+
}
|
|
13380
|
+
function esNumerico(moleculeType) {
|
|
13381
|
+
return moleculeType === "INPUT_CURRENCY" || moleculeType === "INPUT_NUMBER";
|
|
13382
|
+
}
|
|
13383
|
+
function aTexto(valor, uiProps, moleculeType) {
|
|
13384
|
+
if (valor == null || valor === "") return "";
|
|
13385
|
+
if (typeof valor === "boolean") return valor ? "S\xED" : "No";
|
|
13386
|
+
if (esNumerico(moleculeType)) {
|
|
13387
|
+
const n = Number(String(valor).replace(/[^\d.-]/g, ""));
|
|
13388
|
+
if (Number.isFinite(n)) return n.toLocaleString();
|
|
13389
|
+
}
|
|
13390
|
+
if (typeof File !== "undefined" && valor instanceof File) return valor.name;
|
|
13391
|
+
if (Array.isArray(valor)) {
|
|
13392
|
+
const partes = valor.map((v) => aTexto(v, uiProps, moleculeType)).filter(Boolean);
|
|
13393
|
+
return partes.join(", ");
|
|
13394
|
+
}
|
|
13395
|
+
if (typeof valor === "object") {
|
|
13396
|
+
const o = valor;
|
|
13397
|
+
for (const clave of ["label", "address", "name", "text", "value"]) {
|
|
13398
|
+
if (typeof o[clave] === "string" && o[clave]) return o[clave];
|
|
13399
|
+
}
|
|
13400
|
+
return "";
|
|
13401
|
+
}
|
|
13402
|
+
return etiquetaDeOpcion(valor, uiProps) ?? String(valor);
|
|
13403
|
+
}
|
|
13404
|
+
function resumenParaConfirmar(campos, datos) {
|
|
13405
|
+
if (!datos) return [];
|
|
13406
|
+
const lineas = [];
|
|
13407
|
+
for (const campo of campos) {
|
|
13408
|
+
const valor = aTexto(datos[campo.name], campo.uiProps, campo.moleculeType);
|
|
13409
|
+
if (!valor) continue;
|
|
13410
|
+
lineas.push({ label: campo.label ?? campo.name, valor });
|
|
13411
|
+
}
|
|
13412
|
+
return lineas;
|
|
13413
|
+
}
|
|
13414
|
+
|
|
13379
13415
|
const useAnchoPropio = () => {
|
|
13380
13416
|
const ref = React.useRef(null);
|
|
13381
13417
|
const [ancho, setAncho] = React.useState(null);
|
|
@@ -13820,6 +13856,10 @@ function Crud({
|
|
|
13820
13856
|
return "Formulario";
|
|
13821
13857
|
}
|
|
13822
13858
|
};
|
|
13859
|
+
const resumenConfirmacion = React.useMemo(
|
|
13860
|
+
() => confirmAction === "create" || confirmAction === "edit" ? resumenParaConfirmar(formFields, pendingFormData) : [],
|
|
13861
|
+
[confirmAction, formFields, pendingFormData]
|
|
13862
|
+
);
|
|
13823
13863
|
const getConfirmMessage = () => {
|
|
13824
13864
|
switch (confirmAction) {
|
|
13825
13865
|
case "create":
|
|
@@ -13959,6 +13999,10 @@ function Crud({
|
|
|
13959
13999
|
className: `${COMPONENT_PREFIX}crud__confirm-drawer`,
|
|
13960
14000
|
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${COMPONENT_PREFIX}crud__confirm-content`, children: [
|
|
13961
14001
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: `${COMPONENT_PREFIX}crud__confirm-message`, children: getConfirmMessage() }),
|
|
14002
|
+
resumenConfirmacion.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("dl", { className: `${COMPONENT_PREFIX}crud__confirm-summary`, children: resumenConfirmacion.map((linea) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${COMPONENT_PREFIX}crud__confirm-summary-row`, children: [
|
|
14003
|
+
/* @__PURE__ */ jsxRuntime.jsx("dt", { children: linea.label }),
|
|
14004
|
+
/* @__PURE__ */ jsxRuntime.jsx("dd", { children: linea.valor })
|
|
14005
|
+
] }, linea.label)) }),
|
|
13962
14006
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: `${COMPONENT_PREFIX}crud__confirm-actions`, children: [
|
|
13963
14007
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
13964
14008
|
Button,
|
|
@@ -14133,7 +14177,7 @@ function getFormatter(key) {
|
|
|
14133
14177
|
}
|
|
14134
14178
|
|
|
14135
14179
|
const OPTIONS_LOAD_ERROR = "No se pudieron cargar las opciones. Int\xE9ntalo de nuevo.";
|
|
14136
|
-
function unwrap$
|
|
14180
|
+
function unwrap$4(raw) {
|
|
14137
14181
|
if (raw && typeof raw === "object" && "response" in raw) {
|
|
14138
14182
|
return raw.response;
|
|
14139
14183
|
}
|
|
@@ -14154,7 +14198,7 @@ function resolveBody(body, ctx) {
|
|
|
14154
14198
|
}
|
|
14155
14199
|
async function loadOptions(eventBus, ep, ctx) {
|
|
14156
14200
|
const raw = await fetchViaEventBus(eventBus, ep.service, ep.url, ep.method, resolveBody(ep.body, ctx));
|
|
14157
|
-
let data = unwrap$
|
|
14201
|
+
let data = unwrap$4(raw);
|
|
14158
14202
|
if (ep.response_path && data && typeof data === "object" && !Array.isArray(data)) {
|
|
14159
14203
|
data = data[ep.response_path];
|
|
14160
14204
|
}
|
|
@@ -14192,7 +14236,7 @@ const mensajeDeError = (e, respaldo) => {
|
|
|
14192
14236
|
};
|
|
14193
14237
|
|
|
14194
14238
|
const REFRESH_INTERVAL_MS = 2e4;
|
|
14195
|
-
function unwrap$
|
|
14239
|
+
function unwrap$3(raw) {
|
|
14196
14240
|
if (raw && typeof raw === "object" && "response" in raw) {
|
|
14197
14241
|
return raw.response;
|
|
14198
14242
|
}
|
|
@@ -14241,7 +14285,7 @@ function useReactiveCrud(config, eventBus) {
|
|
|
14241
14285
|
filters
|
|
14242
14286
|
});
|
|
14243
14287
|
assertOk(raw);
|
|
14244
|
-
const data = unwrap$
|
|
14288
|
+
const data = unwrap$3(raw);
|
|
14245
14289
|
let rows = [];
|
|
14246
14290
|
let total = 0;
|
|
14247
14291
|
if (Array.isArray(data)) {
|
|
@@ -14445,6 +14489,20 @@ const FileField = ({
|
|
|
14445
14489
|
] });
|
|
14446
14490
|
};
|
|
14447
14491
|
|
|
14492
|
+
const RESPALDO = { miles: ".", decimal: "," };
|
|
14493
|
+
function separadoresDelLocale(locale) {
|
|
14494
|
+
if (!locale) return RESPALDO;
|
|
14495
|
+
try {
|
|
14496
|
+
const partes = new Intl.NumberFormat(locale).formatToParts(123456789e-2);
|
|
14497
|
+
const miles = partes.find((p) => p.type === "group")?.value;
|
|
14498
|
+
const decimal = partes.find((p) => p.type === "decimal")?.value;
|
|
14499
|
+
if (!miles || !decimal) return RESPALDO;
|
|
14500
|
+
return { miles, decimal };
|
|
14501
|
+
} catch {
|
|
14502
|
+
return RESPALDO;
|
|
14503
|
+
}
|
|
14504
|
+
}
|
|
14505
|
+
|
|
14448
14506
|
const CRUD_TO_FORM_MOLECULE = {
|
|
14449
14507
|
INPUT: "INPUT",
|
|
14450
14508
|
INPUT_NUMBER: "INPUT_NUMBER",
|
|
@@ -14501,6 +14559,8 @@ function ActionFormDrawer({ action, row, idField, eventBus, onExecute, onClose }
|
|
|
14501
14559
|
alive = false;
|
|
14502
14560
|
};
|
|
14503
14561
|
}, [eventBus, action.key, normalFields]);
|
|
14562
|
+
const { locale } = useChatConfig();
|
|
14563
|
+
const separadores = React.useMemo(() => separadoresDelLocale(locale), [locale]);
|
|
14504
14564
|
const fields = React.useMemo(
|
|
14505
14565
|
() => normalFields.map((f) => ({
|
|
14506
14566
|
name: f.name,
|
|
@@ -14511,9 +14571,19 @@ function ActionFormDrawer({ action, row, idField, eventBus, onExecute, onClose }
|
|
|
14511
14571
|
options: f.options ?? optionsByField[f.name],
|
|
14512
14572
|
// SPEC-106 T8 — `uiProps` llega tal cual a la molécula, así que el desplegable dice lo
|
|
14513
14573
|
// 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] } } : {}
|
|
14574
|
+
...optionsErrorByField[f.name] ? { uiProps: { notFoundContent: optionsErrorByField[f.name] } } : {},
|
|
14575
|
+
// SPEC-128 — el dinero se escribe como se escribe AQUÍ.
|
|
14576
|
+
//
|
|
14577
|
+
// Los campos de moneda caían a `thousandSeparator ?? ','`, un valor por defecto en formato
|
|
14578
|
+
// inglés: al teclear 180000 el campo mostraba «180,000» mientras la tarjeta que recibe el
|
|
14579
|
+
// cliente decía «$ 180.000,00 COP». El mismo importe escrito de una manera y leído de otra.
|
|
14580
|
+
//
|
|
14581
|
+
// Se deriva del locale que el host ya declara en la config del chat, no de un valor fijo ni
|
|
14582
|
+
// del navegador: `navigator.language` puede ser `es-419` —español, pero con coma para los
|
|
14583
|
+
// miles— y entonces el resultado dependería del portátil de cada quien.
|
|
14584
|
+
...f.moleculeType === "INPUT_CURRENCY" ? { uiProps: { thousandSeparator: separadores.miles, decimalSeparator: separadores.decimal } } : {}
|
|
14515
14585
|
})),
|
|
14516
|
-
[normalFields, optionsByField, optionsErrorByField]
|
|
14586
|
+
[normalFields, optionsByField, optionsErrorByField, separadores]
|
|
14517
14587
|
);
|
|
14518
14588
|
const validationSchema = React.useMemo(() => buildCrudYupSchema(normalFields), [normalFields]);
|
|
14519
14589
|
const uploadOne = async (f, file, idx) => {
|
|
@@ -15172,6 +15242,95 @@ const FileViewer = ({
|
|
|
15172
15242
|
] });
|
|
15173
15243
|
};
|
|
15174
15244
|
|
|
15245
|
+
function unwrap$2(raw) {
|
|
15246
|
+
if (raw && typeof raw === "object" && "response" in raw) {
|
|
15247
|
+
return raw.response;
|
|
15248
|
+
}
|
|
15249
|
+
return raw;
|
|
15250
|
+
}
|
|
15251
|
+
function hora(iso) {
|
|
15252
|
+
if (!iso) return "";
|
|
15253
|
+
const d = new Date(iso);
|
|
15254
|
+
if (Number.isNaN(d.getTime())) return "";
|
|
15255
|
+
return d.toLocaleString(void 0, { day: "2-digit", month: "short", hour: "2-digit", minute: "2-digit" });
|
|
15256
|
+
}
|
|
15257
|
+
function TranscriptSection({ transcript, values, eventBus }) {
|
|
15258
|
+
const chatId = values[transcript.chatIdField];
|
|
15259
|
+
const id = chatId == null || chatId === "" ? "" : String(chatId);
|
|
15260
|
+
const [datos, setDatos] = React.useState(null);
|
|
15261
|
+
const [cargando, setCargando] = React.useState(true);
|
|
15262
|
+
const [fallo, setFallo] = React.useState(false);
|
|
15263
|
+
React.useEffect(() => {
|
|
15264
|
+
if (!eventBus || !id) {
|
|
15265
|
+
setCargando(false);
|
|
15266
|
+
return;
|
|
15267
|
+
}
|
|
15268
|
+
let vivo = true;
|
|
15269
|
+
setCargando(true);
|
|
15270
|
+
setFallo(false);
|
|
15271
|
+
void (async () => {
|
|
15272
|
+
try {
|
|
15273
|
+
const raw = await fetchViaEventBus(
|
|
15274
|
+
eventBus,
|
|
15275
|
+
transcript.get.service,
|
|
15276
|
+
transcript.get.url,
|
|
15277
|
+
transcript.get.method ?? "POST",
|
|
15278
|
+
{ [transcript.param ?? "chat_id"]: id }
|
|
15279
|
+
);
|
|
15280
|
+
if (vivo) {
|
|
15281
|
+
setDatos(unwrap$2(raw) ?? {});
|
|
15282
|
+
setCargando(false);
|
|
15283
|
+
}
|
|
15284
|
+
} catch {
|
|
15285
|
+
if (vivo) {
|
|
15286
|
+
setFallo(true);
|
|
15287
|
+
setCargando(false);
|
|
15288
|
+
}
|
|
15289
|
+
}
|
|
15290
|
+
})();
|
|
15291
|
+
return () => {
|
|
15292
|
+
vivo = false;
|
|
15293
|
+
};
|
|
15294
|
+
}, [eventBus, id, transcript]);
|
|
15295
|
+
if (!id) return null;
|
|
15296
|
+
const lineas = datos?.lines ?? [];
|
|
15297
|
+
const dijoAlgo = (datos?.from_user ?? 0) > 0;
|
|
15298
|
+
const nombres = {
|
|
15299
|
+
user: transcript.labels?.user ?? "Cliente",
|
|
15300
|
+
assistant: transcript.labels?.assistant ?? "Asistente"
|
|
15301
|
+
};
|
|
15302
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-crud-transcript", children: [
|
|
15303
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "px-chat-crud-transcript__title", children: transcript.title ?? "Conversaci\xF3n" }),
|
|
15304
|
+
cargando && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-transcript__note", children: "Cargando\u2026" }),
|
|
15305
|
+
!cargando && fallo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-transcript__note", children: "No se pudo cargar la conversaci\xF3n." }),
|
|
15306
|
+
!cargando && !fallo && !dijoAlgo && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-transcript__note", children: transcript.silentText ?? "Todav\xEDa no ha escrito nada." }),
|
|
15307
|
+
!cargando && !fallo && lineas.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("ol", { className: "px-chat-crud-transcript__lines", children: lineas.map((l, i) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
15308
|
+
"li",
|
|
15309
|
+
{
|
|
15310
|
+
className: [
|
|
15311
|
+
"px-chat-crud-transcript__line",
|
|
15312
|
+
l.rol === "user" ? "is-user" : "is-assistant"
|
|
15313
|
+
].join(" "),
|
|
15314
|
+
children: [
|
|
15315
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-chat-crud-transcript__who", children: [
|
|
15316
|
+
l.rol === "user" ? nombres.user : nombres.assistant,
|
|
15317
|
+
hora(l.created_date) && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-crud-transcript__when", children: hora(l.created_date) })
|
|
15318
|
+
] }),
|
|
15319
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-crud-transcript__text", children: l.text })
|
|
15320
|
+
]
|
|
15321
|
+
},
|
|
15322
|
+
`${i}-${l.created_date ?? ""}`
|
|
15323
|
+
)) }),
|
|
15324
|
+
!cargando && !fallo && (datos?.total ?? 0) > lineas.length && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-crud-transcript__note", children: [
|
|
15325
|
+
"Se muestran los \xFAltimos ",
|
|
15326
|
+
lineas.length,
|
|
15327
|
+
" de ",
|
|
15328
|
+
datos?.total,
|
|
15329
|
+
" mensajes."
|
|
15330
|
+
] })
|
|
15331
|
+
] });
|
|
15332
|
+
}
|
|
15333
|
+
|
|
15175
15334
|
function unwrap$1(raw) {
|
|
15176
15335
|
if (raw && typeof raw === "object" && "response" in raw) {
|
|
15177
15336
|
return raw.response;
|
|
@@ -15300,6 +15459,7 @@ function DetailDrawer({ row, config, eventBus, onClose, loadedOptions }) {
|
|
|
15300
15459
|
] })
|
|
15301
15460
|
] }, f.name);
|
|
15302
15461
|
}) }),
|
|
15462
|
+
config.transcript && /* @__PURE__ */ jsxRuntime.jsx(TranscriptSection, { transcript: config.transcript, values, eventBus }),
|
|
15303
15463
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-reactive-crud-detail__photos", children: [
|
|
15304
15464
|
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "px-chat-reactive-crud-detail__photos-title", children: "Fotos y documentos" }),
|
|
15305
15465
|
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." })
|
|
@@ -15788,7 +15948,8 @@ function usePlaceSuggestions(query, enabled) {
|
|
|
15788
15948
|
return {
|
|
15789
15949
|
lat: typeof loc.lat === "function" ? loc.lat() : loc.lat,
|
|
15790
15950
|
lng: typeof loc.lng === "function" ? loc.lng() : loc.lng,
|
|
15791
|
-
address: String(place.formattedAddress ?? "")
|
|
15951
|
+
address: limpiarDireccion(String(place.formattedAddress ?? ""))
|
|
15952
|
+
// SPEC-131 T6
|
|
15792
15953
|
};
|
|
15793
15954
|
} catch {
|
|
15794
15955
|
return null;
|
|
@@ -15798,13 +15959,27 @@ function usePlaceSuggestions(query, enabled) {
|
|
|
15798
15959
|
);
|
|
15799
15960
|
return { suggestions, resolve, clear: () => setSuggestions([]) };
|
|
15800
15961
|
}
|
|
15962
|
+
function limpiarDireccion(address) {
|
|
15963
|
+
const normal = (s) => s.trim().toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "");
|
|
15964
|
+
const vistos = /* @__PURE__ */ new Set();
|
|
15965
|
+
const tramos = [];
|
|
15966
|
+
for (const tramo of address.split(",")) {
|
|
15967
|
+
const limpio = tramo.trim();
|
|
15968
|
+
if (!limpio) continue;
|
|
15969
|
+
const clave = normal(limpio);
|
|
15970
|
+
if (vistos.has(clave)) continue;
|
|
15971
|
+
vistos.add(clave);
|
|
15972
|
+
tramos.push(limpio);
|
|
15973
|
+
}
|
|
15974
|
+
return tramos.join(", ");
|
|
15975
|
+
}
|
|
15801
15976
|
function reverseGeocode(lat, lng) {
|
|
15802
15977
|
return new Promise((resolve) => {
|
|
15803
15978
|
const maps = window.google?.maps;
|
|
15804
15979
|
if (!maps?.Geocoder) return resolve(null);
|
|
15805
15980
|
new maps.Geocoder().geocode({ location: { lat, lng } }, (results, status) => {
|
|
15806
15981
|
if (status !== "OK" || !results?.length) return resolve(null);
|
|
15807
|
-
resolve(String(results[0].formatted_address ?? "") || null);
|
|
15982
|
+
resolve(limpiarDireccion(String(results[0].formatted_address ?? "")) || null);
|
|
15808
15983
|
});
|
|
15809
15984
|
});
|
|
15810
15985
|
}
|
|
@@ -15961,6 +16136,10 @@ function toRenderField(f, loaded, eventBus, mapsApiKey, loadError) {
|
|
|
15961
16136
|
showInModes: f.showInModes,
|
|
15962
16137
|
required: f.required,
|
|
15963
16138
|
placeholder: f.placeholder,
|
|
16139
|
+
// SPEC-131 T7 — la fila entera: al elegir la dirección se despliega el mapa de verificación
|
|
16140
|
+
// y, a media fila, su campo hermano se quedaba con ~400px de blanco al lado. Medido entre
|
|
16141
|
+
// «¿En qué situación está?» y «¿A dónde lo llevamos?» del formulario de solicitud.
|
|
16142
|
+
gridSpan: 2,
|
|
15964
16143
|
uiProps: {
|
|
15965
16144
|
// SPEC-074 — `error` viene del render de CUSTOM (DynamicForm ya lo pasaba) y aquí se
|
|
15966
16145
|
// desechaba: el campo obligatorio más importante era el único mudo.
|
|
@@ -16006,6 +16185,10 @@ function matchesVisibleWhen(a, row) {
|
|
|
16006
16185
|
if (!a.visibleWhen) return true;
|
|
16007
16186
|
return cumplenTodas(a.visibleWhen, row);
|
|
16008
16187
|
}
|
|
16188
|
+
function laQueTocaAhora(actions, row) {
|
|
16189
|
+
const candidatas = actions.filter((a) => a.ahoraToca && cumplenTodas(a.ahoraToca, row));
|
|
16190
|
+
return candidatas.length === 1 ? candidatas[0] : void 0;
|
|
16191
|
+
}
|
|
16009
16192
|
function condicionesDeshabilitado(a) {
|
|
16010
16193
|
if (!a.disabledWhen) return [];
|
|
16011
16194
|
return Array.isArray(a.disabledWhen) ? a.disabledWhen : [a.disabledWhen];
|
|
@@ -16326,7 +16509,7 @@ function DeadlineCountdown({ deadline, label, expiredLabel }) {
|
|
|
16326
16509
|
}
|
|
16327
16510
|
|
|
16328
16511
|
function ReactiveCrudItemChat({ component, eventBus }) {
|
|
16329
|
-
const { resolveModuleConfig } = useChatConfig();
|
|
16512
|
+
const { resolveModuleConfig, resolveMomento } = useChatConfig();
|
|
16330
16513
|
const props = component.props ?? {};
|
|
16331
16514
|
const top = component;
|
|
16332
16515
|
const pick = (key) => props[key] !== void 0 ? props[key] : top[key];
|
|
@@ -16334,7 +16517,11 @@ function ReactiveCrudItemChat({ component, eventBus }) {
|
|
|
16334
16517
|
const recordId = pick("record_id") ?? pick("recordId") ?? pick("id") ?? pick("service_id");
|
|
16335
16518
|
const recordLabel = pick("record_label") ?? pick("label");
|
|
16336
16519
|
const allowedRaw = pick("actions");
|
|
16337
|
-
const
|
|
16520
|
+
const allowedLegacy = Array.isArray(allowedRaw) && allowedRaw.length > 0 ? allowedRaw : void 0;
|
|
16521
|
+
const momento = pick("momento");
|
|
16522
|
+
const delMomento = momento && resolveMomento ? resolveMomento(momento) : void 0;
|
|
16523
|
+
const allowed = delMomento ?? allowedLegacy;
|
|
16524
|
+
const sinAcciones = delMomento?.length === 0;
|
|
16338
16525
|
const config = typeof moduleKey === "string" && resolveModuleConfig ? resolveModuleConfig(moduleKey) : void 0;
|
|
16339
16526
|
if (!config || recordId == null || recordId === "") return null;
|
|
16340
16527
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -16344,11 +16531,12 @@ function ReactiveCrudItemChat({ component, eventBus }) {
|
|
|
16344
16531
|
recordId: String(recordId),
|
|
16345
16532
|
recordLabel,
|
|
16346
16533
|
allowed: Array.isArray(allowed) ? allowed.map(String) : void 0,
|
|
16534
|
+
sinAcciones,
|
|
16347
16535
|
eventBus
|
|
16348
16536
|
}
|
|
16349
16537
|
);
|
|
16350
16538
|
}
|
|
16351
|
-
function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus }) {
|
|
16539
|
+
function ServiceActionsPanel({ config, recordId, recordLabel, allowed, sinAcciones, eventBus }) {
|
|
16352
16540
|
const { chatIsForeign } = useChatConfig();
|
|
16353
16541
|
const crud = useReactiveCrud(config, eventBus);
|
|
16354
16542
|
const [activeAction, setActiveAction] = React.useState(null);
|
|
@@ -16397,9 +16585,26 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
|
|
|
16397
16585
|
}, [recordId]);
|
|
16398
16586
|
const gastada = !esUltima;
|
|
16399
16587
|
const actions = React.useMemo(() => {
|
|
16400
|
-
if (!row
|
|
16401
|
-
|
|
16588
|
+
if (!row) return [];
|
|
16589
|
+
if (gastada) {
|
|
16590
|
+
const hechas = (config.rowActions ?? []).filter((a) => !allowed || allowed.includes(a.key)).filter((a) => matchesDoneWhen(a, row));
|
|
16591
|
+
const vistas = /* @__PURE__ */ new Set();
|
|
16592
|
+
return hechas.filter((a) => {
|
|
16593
|
+
const linea = a.doneLabel ?? a.label;
|
|
16594
|
+
if (vistas.has(linea)) return false;
|
|
16595
|
+
vistas.add(linea);
|
|
16596
|
+
return true;
|
|
16597
|
+
});
|
|
16598
|
+
}
|
|
16599
|
+
const visibles = (config.rowActions ?? []).filter((a) => !allowed || allowed.includes(a.key)).filter((a) => matchesVisibleWhen(a, row));
|
|
16600
|
+
const toca = laQueTocaAhora(visibles, row);
|
|
16601
|
+
if (!toca) return visibles;
|
|
16602
|
+
return [toca, ...visibles.filter((a) => a.key !== toca.key)];
|
|
16402
16603
|
}, [config.rowActions, row, allowed, gastada]);
|
|
16604
|
+
const claveQueToca = React.useMemo(
|
|
16605
|
+
() => row && !gastada ? laQueTocaAhora(actions, row)?.key : void 0,
|
|
16606
|
+
[actions, row, gastada]
|
|
16607
|
+
);
|
|
16403
16608
|
const title = recordLabel ?? config.title ?? "Servicio";
|
|
16404
16609
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-crud-item", ref: raiz, "data-panel-record": recordId, children: [
|
|
16405
16610
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-item__header", children: title }),
|
|
@@ -16410,7 +16615,7 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
|
|
|
16410
16615
|
crud.loading && !row && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-item__hint", children: "Cargando\u2026" }),
|
|
16411
16616
|
!crud.loading && !row && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-item__hint", children: "No se encontr\xF3 el servicio." }),
|
|
16412
16617
|
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(
|
|
16618
|
+
row && !gastada && config.deadline && typeof row[config.deadline.field] === "string" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
16414
16619
|
DeadlineCountdown,
|
|
16415
16620
|
{
|
|
16416
16621
|
deadline: row[config.deadline.field],
|
|
@@ -16421,7 +16626,7 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
|
|
|
16421
16626
|
row && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-crud-item__actions", children: [
|
|
16422
16627
|
config.detail && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "px-chat-crud-item__action", onClick: () => setDetailRow(row), children: "Ver" }),
|
|
16423
16628
|
actions.map((a) => {
|
|
16424
|
-
const disabled = Boolean(chatIsForeign) || matchesDisabledWhen(a, row);
|
|
16629
|
+
const disabled = gastada || Boolean(chatIsForeign) || matchesDisabledWhen(a, row);
|
|
16425
16630
|
const motivo = chatIsForeign ? "Esta conversaci\xF3n es de otra persona" : disabledReasonFor(a, row);
|
|
16426
16631
|
const done = matchesDoneWhen(a, row);
|
|
16427
16632
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -16431,13 +16636,18 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
|
|
|
16431
16636
|
className: [
|
|
16432
16637
|
"px-chat-crud-item__action",
|
|
16433
16638
|
a.intent === "danger" ? "is-danger" : "",
|
|
16434
|
-
disabled && motivo ? "is-con-motivo" : ""
|
|
16639
|
+
disabled && motivo ? "is-con-motivo" : "",
|
|
16640
|
+
// SPEC-129 T6 — lo hecho se pinta como un acta, no como un botón apagado.
|
|
16641
|
+
gastada ? "is-hecho" : "",
|
|
16642
|
+
// SPEC-127 T4 — señalada, pero solo si de verdad se puede pulsar: destacar una
|
|
16643
|
+
// acción apagada sería dirigir a alguien a una puerta cerrada.
|
|
16644
|
+
a.key === claveQueToca && !disabled ? "is-ahora" : ""
|
|
16435
16645
|
].filter(Boolean).join(" "),
|
|
16436
16646
|
disabled,
|
|
16437
16647
|
onClick: () => a.form ? setActiveAction({ action: a, row }) : crud.runEndpoints(a.endpoints ?? [a.endpoint], { ...row, id: row[config.idField] }),
|
|
16438
16648
|
children: [
|
|
16439
16649
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "px-chat-crud-item__action-texts", children: [
|
|
16440
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: a.label }),
|
|
16650
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: gastada && a.doneLabel ? a.doneLabel : a.label }),
|
|
16441
16651
|
disabled && motivo && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-crud-item__action-reason", children: motivo })
|
|
16442
16652
|
] }),
|
|
16443
16653
|
done && /* @__PURE__ */ jsxRuntime.jsx(Icon$1, { type: "check-circle", width: 18, height: 18, className: "px-chat-crud-item__done", "aria-label": "Hecho" })
|
|
@@ -16446,7 +16656,7 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
|
|
|
16446
16656
|
a.key
|
|
16447
16657
|
);
|
|
16448
16658
|
}),
|
|
16449
|
-
actions.length === 0 && !config.detail && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-item__hint", children: "Sin acciones disponibles." })
|
|
16659
|
+
actions.length === 0 && !config.detail && !sinAcciones && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-crud-item__hint", children: "Sin acciones disponibles." })
|
|
16450
16660
|
] }),
|
|
16451
16661
|
activeAction && /* @__PURE__ */ jsxRuntime.jsx(
|
|
16452
16662
|
ActionFormDrawer,
|
|
@@ -16554,6 +16764,8 @@ const ServicesMap = ({ config, eventBus, apiKey, filter, fill }) => {
|
|
|
16554
16764
|
const { service, url, method, payloadMap } = config.data.list;
|
|
16555
16765
|
void fetchViaEventBus(eventBus, service, url, method ?? "POST", {
|
|
16556
16766
|
...payloadMap,
|
|
16767
|
+
// SPEC-131 T6 — el del config primero, el de la instancia después: quien acota manda.
|
|
16768
|
+
...config.defaultFilter ?? {},
|
|
16557
16769
|
...filter ?? {}
|
|
16558
16770
|
}).then((res) => {
|
|
16559
16771
|
if (!alive) return;
|
|
@@ -16666,7 +16878,7 @@ const ServicesMap = ({ config, eventBus, apiKey, filter, fill }) => {
|
|
|
16666
16878
|
),
|
|
16667
16879
|
simulated > 0 && ` \xB7 ${config.live?.labels?.simulatedText ?? "incluye posiciones simuladas"}`
|
|
16668
16880
|
] }),
|
|
16669
|
-
missing > 0 && /* @__PURE__ */ jsxRuntime.jsx("p", { className: `${CLASS$6}__note`, children: (labels.missingText ?? "{n} sin ubicaci\xF3n registrada").replace("{n}", String(missing)) }),
|
|
16881
|
+
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
16882
|
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
16883
|
"{n}",
|
|
16672
16884
|
String(outside)
|
|
@@ -18707,6 +18919,10 @@ const useInputFocus = ({
|
|
|
18707
18919
|
};
|
|
18708
18920
|
};
|
|
18709
18921
|
|
|
18922
|
+
function reservaNecesaria(clientHeight, scrollHeight, targetTop) {
|
|
18923
|
+
const debajoDelObjetivo = scrollHeight - targetTop;
|
|
18924
|
+
return Math.max(0, clientHeight - debajoDelObjetivo);
|
|
18925
|
+
}
|
|
18710
18926
|
const useAutoScroll = ({
|
|
18711
18927
|
messagesEndRef,
|
|
18712
18928
|
messagesContainerRef
|
|
@@ -18725,11 +18941,12 @@ const useAutoScroll = ({
|
|
|
18725
18941
|
const container = messagesContainerRef.current;
|
|
18726
18942
|
const spacer = messagesEndRef.current;
|
|
18727
18943
|
if (!container || !spacer || !target) return;
|
|
18728
|
-
spacer.style.minHeight =
|
|
18944
|
+
spacer.style.minHeight = "0px";
|
|
18729
18945
|
const containerRect = container.getBoundingClientRect();
|
|
18730
18946
|
const msgRect = target.getBoundingClientRect();
|
|
18731
18947
|
const padTop = parseFloat(getComputedStyle(container).paddingTop) || 0;
|
|
18732
18948
|
const targetTop = msgRect.top - containerRect.top + container.scrollTop - padTop;
|
|
18949
|
+
spacer.style.minHeight = `${reservaNecesaria(container.clientHeight, container.scrollHeight, targetTop)}px`;
|
|
18733
18950
|
container.scrollTo({ top: targetTop, behavior: "smooth" });
|
|
18734
18951
|
}, [messagesContainerRef, messagesEndRef]);
|
|
18735
18952
|
const last = React.useCallback((selector) => {
|
|
@@ -18771,15 +18988,33 @@ const useAutoScroll = ({
|
|
|
18771
18988
|
});
|
|
18772
18989
|
}, 150);
|
|
18773
18990
|
}, [doScroll]);
|
|
18774
|
-
const
|
|
18991
|
+
const aterrizarAlFinal = React.useCallback(() => {
|
|
18992
|
+
const container = messagesContainerRef.current;
|
|
18993
|
+
if (!container) return;
|
|
18994
|
+
resetSpacer();
|
|
18995
|
+
const hasta = Date.now() + 1e3;
|
|
18996
|
+
let ultimoAlto = -1;
|
|
18997
|
+
const pegar = () => {
|
|
18998
|
+
const c = messagesContainerRef.current;
|
|
18999
|
+
if (!c) return;
|
|
19000
|
+
if (c.scrollHeight !== ultimoAlto) {
|
|
19001
|
+
ultimoAlto = c.scrollHeight;
|
|
19002
|
+
c.scrollTop = c.scrollHeight;
|
|
19003
|
+
}
|
|
19004
|
+
if (Date.now() < hasta) requestAnimationFrame(pegar);
|
|
19005
|
+
};
|
|
19006
|
+
requestAnimationFrame(pegar);
|
|
19007
|
+
}, [messagesContainerRef, resetSpacer]);
|
|
19008
|
+
const scrollToBottom = React.useCallback((suave = true) => {
|
|
18775
19009
|
cancelPending();
|
|
18776
19010
|
resetSpacer();
|
|
18777
19011
|
requestAnimationFrame(() => {
|
|
19012
|
+
const comportamiento = suave ? "smooth" : "auto";
|
|
18778
19013
|
const container = messagesContainerRef.current;
|
|
18779
19014
|
if (container) {
|
|
18780
|
-
container.scrollTo({ top: container.scrollHeight, behavior:
|
|
19015
|
+
container.scrollTo({ top: container.scrollHeight, behavior: comportamiento });
|
|
18781
19016
|
} else {
|
|
18782
|
-
messagesEndRef.current?.scrollIntoView({ behavior:
|
|
19017
|
+
messagesEndRef.current?.scrollIntoView({ behavior: comportamiento, block: "end" });
|
|
18783
19018
|
}
|
|
18784
19019
|
});
|
|
18785
19020
|
}, [cancelPending, resetSpacer, messagesContainerRef, messagesEndRef]);
|
|
@@ -18787,7 +19022,9 @@ const useAutoScroll = ({
|
|
|
18787
19022
|
scrollToLastUserMessage,
|
|
18788
19023
|
pinLastUserMessage,
|
|
18789
19024
|
scrollToProactive,
|
|
18790
|
-
scrollToBottom
|
|
19025
|
+
scrollToBottom,
|
|
19026
|
+
aterrizarAlFinal
|
|
19027
|
+
// SPEC-131 T3
|
|
18791
19028
|
};
|
|
18792
19029
|
};
|
|
18793
19030
|
|
|
@@ -19340,7 +19577,7 @@ const Chat = ({
|
|
|
19340
19577
|
usePreventOverscroll();
|
|
19341
19578
|
const { showThinking, scrollButtonState, scrollToTopPending } = useChatStore();
|
|
19342
19579
|
const { attachments, handleAttachmentsChange, clearAttachments } = useAttachments();
|
|
19343
|
-
const { scrollToBottom, scrollToLastUserMessage, pinLastUserMessage, scrollToProactive } = useAutoScroll({
|
|
19580
|
+
const { scrollToBottom, scrollToLastUserMessage, pinLastUserMessage, scrollToProactive, aterrizarAlFinal } = useAutoScroll({
|
|
19344
19581
|
messagesEndRef,
|
|
19345
19582
|
messagesContainerRef
|
|
19346
19583
|
});
|
|
@@ -19368,11 +19605,23 @@ const Chat = ({
|
|
|
19368
19605
|
}
|
|
19369
19606
|
}, [scrollToTopPending, scrollToLastUserMessage]);
|
|
19370
19607
|
React.useEffect(() => {
|
|
19608
|
+
if (messages[messages.length - 1]?.proactive) return;
|
|
19371
19609
|
const spacer = messagesEndRef.current;
|
|
19372
19610
|
if (spacer && spacer.style.minHeight && spacer.style.minHeight !== "0px") {
|
|
19373
19611
|
pinLastUserMessage();
|
|
19374
19612
|
}
|
|
19375
19613
|
}, [messages]);
|
|
19614
|
+
const yaAterrizo = React.useRef(false);
|
|
19615
|
+
React.useEffect(() => {
|
|
19616
|
+
if (messages.length === 0) {
|
|
19617
|
+
yaAterrizo.current = false;
|
|
19618
|
+
return;
|
|
19619
|
+
}
|
|
19620
|
+
if (yaAterrizo.current) return;
|
|
19621
|
+
yaAterrizo.current = true;
|
|
19622
|
+
if (messages[messages.length - 1]?.proactive) return;
|
|
19623
|
+
aterrizarAlFinal();
|
|
19624
|
+
}, [messages, aterrizarAlFinal]);
|
|
19376
19625
|
const lastProactiveIdRef = React.useRef(void 0);
|
|
19377
19626
|
React.useEffect(() => {
|
|
19378
19627
|
const last = messages[messages.length - 1];
|
|
@@ -19490,7 +19739,7 @@ const Chat = ({
|
|
|
19490
19739
|
{
|
|
19491
19740
|
className: `${COMPONENT_PREFIX$1}chat__scroll-to-bottom`,
|
|
19492
19741
|
variant: "circle",
|
|
19493
|
-
onClick: scrollToBottom,
|
|
19742
|
+
onClick: () => scrollToBottom(),
|
|
19494
19743
|
"aria-label": "Ir al final",
|
|
19495
19744
|
icon: /* @__PURE__ */ jsxRuntime.jsxs("svg", { xmlns: "http://www.w3.org/2000/svg", width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
|
|
19496
19745
|
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 8v8", strokeWidth: "2", strokeLinecap: "round" }),
|