pixelon 0.3.83 → 0.4.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
@@ -1672,7 +1672,7 @@ function getSubmitActionId(component) {
1672
1672
  }
1673
1673
  const TERMINAL_STATUS = /* @__PURE__ */ new Set(["answered", "cancelled", "expired"]);
1674
1674
  const DISPLAY_COMPONENTS = /* @__PURE__ */ new Set(["card", "badge", "reactive_form", "carousel"]);
1675
- const PERSISTENT_COMPONENTS = /* @__PURE__ */ new Set(["reactive_crud", "reactive_crud_item", "price_negotiation", "chat_navigator", "map_view", "services_map", "service_shortcuts", "user_tools"]);
1675
+ const PERSISTENT_COMPONENTS = /* @__PURE__ */ new Set(["reactive_crud", "reactive_crud_item", "chat_navigator", "map_view", "user_tools"]);
1676
1676
  const PURE_DISPLAY_COMPONENTS = /* @__PURE__ */ new Set(["card", "badge"]);
1677
1677
 
1678
1678
  const AnsweredSummary = ({ component }) => {
@@ -16188,7 +16188,7 @@ function readCreated(messageId) {
16188
16188
  }
16189
16189
  }
16190
16190
  function ReactiveCrudChat({ component, eventBus, assistantMessageId }) {
16191
- const { resolveModuleConfig } = useChatConfig();
16191
+ const { resolveModuleConfig, chatIsForeign } = useChatConfig();
16192
16192
  const [open, setOpen] = React.useState(false);
16193
16193
  const [created, setCreated] = React.useState(() => readCreated(assistantMessageId));
16194
16194
  const props = component.props ?? {};
@@ -16227,8 +16227,8 @@ function ReactiveCrudChat({ component, eventBus, assistantMessageId }) {
16227
16227
  type: "button",
16228
16228
  className: `px-chat-reactive-crud-trigger${done ? " px-chat-reactive-crud-trigger--done" : ""}`,
16229
16229
  onClick: () => setOpen(true),
16230
- disabled: done,
16231
- "aria-disabled": done,
16230
+ disabled: done || Boolean(chatIsForeign),
16231
+ "aria-disabled": done || Boolean(chatIsForeign),
16232
16232
  children: [
16233
16233
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-reactive-crud-trigger__icon", children: done ? /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "18", height: "18", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
16234
16234
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M22 11.08V12a10 10 0 1 1-5.93-9.14" }),
@@ -16332,7 +16332,8 @@ function ReactiveCrudItemChat({ component, eventBus }) {
16332
16332
  const moduleKey = pick("module");
16333
16333
  const recordId = pick("record_id") ?? pick("recordId") ?? pick("id") ?? pick("service_id");
16334
16334
  const recordLabel = pick("record_label") ?? pick("label");
16335
- const allowed = pick("actions");
16335
+ const allowedRaw = pick("actions");
16336
+ const allowed = Array.isArray(allowedRaw) && allowedRaw.length > 0 ? allowedRaw : void 0;
16336
16337
  const config = typeof moduleKey === "string" && resolveModuleConfig ? resolveModuleConfig(moduleKey) : void 0;
16337
16338
  if (!config || recordId == null || recordId === "") return null;
16338
16339
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -16347,6 +16348,7 @@ function ReactiveCrudItemChat({ component, eventBus }) {
16347
16348
  );
16348
16349
  }
16349
16350
  function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus }) {
16351
+ const { chatIsForeign } = useChatConfig();
16350
16352
  const crud = useReactiveCrud(config, eventBus);
16351
16353
  const [activeAction, setActiveAction] = React.useState(null);
16352
16354
  const [detailRow, setDetailRow] = React.useState(null);
@@ -16418,8 +16420,8 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
16418
16420
  row && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-crud-item__actions", children: [
16419
16421
  config.detail && /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: "px-chat-crud-item__action", onClick: () => setDetailRow(row), children: "Ver" }),
16420
16422
  actions.map((a) => {
16421
- const disabled = matchesDisabledWhen(a, row);
16422
- const motivo = disabledReasonFor(a, row);
16423
+ const disabled = Boolean(chatIsForeign) || matchesDisabledWhen(a, row);
16424
+ const motivo = chatIsForeign ? "Esta conversaci\xF3n es de otra persona" : disabledReasonFor(a, row);
16423
16425
  const done = matchesDoneWhen(a, row);
16424
16426
  return /* @__PURE__ */ jsxRuntime.jsxs(
16425
16427
  "button",
@@ -16460,107 +16462,6 @@ function ServiceActionsPanel({ config, recordId, recordLabel, allowed, eventBus
16460
16462
  ] });
16461
16463
  }
16462
16464
 
16463
- const ACTOR_LABEL = { COLLA: "la empresa aliada", ADMIN: "la operadora" };
16464
- const TURN_GATED = /* @__PURE__ */ new Set(["accept_price", "propose_price"]);
16465
- function PriceNegotiationChat({ component, eventBus }) {
16466
- const { resolveModuleConfig } = useChatConfig();
16467
- const props = component.props ?? {};
16468
- const top = component;
16469
- const pick = (key) => props[key] !== void 0 ? props[key] : top[key];
16470
- const moduleKey = pick("module");
16471
- const recordId = pick("record_id") ?? pick("service_id") ?? pick("id");
16472
- const recordLabel = pick("record_label") ?? pick("label");
16473
- const allowed = pick("actions");
16474
- const config = typeof moduleKey === "string" && resolveModuleConfig ? resolveModuleConfig(moduleKey) : void 0;
16475
- if (!config || recordId == null || recordId === "") return null;
16476
- return /* @__PURE__ */ jsxRuntime.jsx(
16477
- NegotiationPanel,
16478
- {
16479
- config,
16480
- recordId: String(recordId),
16481
- recordLabel,
16482
- allowed: Array.isArray(allowed) ? allowed.map(String) : void 0,
16483
- eventBus
16484
- }
16485
- );
16486
- }
16487
- function NegotiationPanel({ config, recordId, recordLabel, allowed, eventBus }) {
16488
- const crud = useReactiveCrud(config, eventBus);
16489
- const [activeAction, setActiveAction] = React.useState(null);
16490
- const row = React.useMemo(
16491
- () => crud.rows.find((r) => String(r[config.idField]) === recordId),
16492
- [crud.rows, config.idField, recordId]
16493
- );
16494
- const actions = React.useMemo(() => {
16495
- if (!row) return [];
16496
- return (config.rowActions ?? []).filter((a) => !allowed || allowed.includes(a.key)).filter((a) => matchesVisibleWhen(a, row));
16497
- }, [config.rowActions, row, allowed]);
16498
- const title = recordLabel ?? config.title ?? "Servicio";
16499
- const proposed = row?.proposed_price;
16500
- const proposer = row?.price_proposed_by;
16501
- const myTurn = row?.my_turn === true || String(row?.my_turn) === "true";
16502
- const hasOffer = proposed != null && proposed !== "";
16503
- const canPropose = !allowed || allowed.includes("propose_price");
16504
- const agreed = row?.price_amount;
16505
- const esperandoRespuesta = ["QUOTED", "PRE_ASSIGNED"].includes(String(row?.status ?? ""));
16506
- const cerrada = !esperandoRespuesta && agreed != null && agreed !== "";
16507
- const ofertaMia = hasOffer && !myTurn;
16508
- const quienOfrece = ofertaMia ? "tu oferta" : `oferta de ${ACTOR_LABEL[proposer ?? ""] ?? "la otra parte"}`;
16509
- return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-price-neg", children: [
16510
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-price-neg__header", children: [
16511
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-price-neg__title", children: title }),
16512
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: `px-chat-price-neg__badge${cerrada ? " is-closed" : ""}`, children: cerrada ? "Precio acordado" : canPropose ? "Negociaci\xF3n de precio" : "Cotizaci\xF3n" })
16513
- ] }),
16514
- crud.actionError && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-price-neg__error", role: "alert", children: [
16515
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: crud.actionError }),
16516
- /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", "aria-label": "Cerrar", onClick: crud.clearActionError, children: "\u2715" })
16517
- ] }),
16518
- crud.loading && !row && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-price-neg__hint", children: "Cargando\u2026" }),
16519
- !crud.loading && !row && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-price-neg__hint", children: "No se encontr\xF3 el servicio." }),
16520
- row && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16521
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-price-neg__offer", children: cerrada ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16522
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-price-neg__amount", children: /* @__PURE__ */ jsxRuntime.jsx(CurrencyDisplay, { value: agreed }) }),
16523
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-price-neg__by", children: "precio acordado" })
16524
- ] }) : hasOffer ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
16525
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-price-neg__amount", children: /* @__PURE__ */ jsxRuntime.jsx(CurrencyDisplay, { value: proposed }) }),
16526
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-price-neg__by", children: canPropose ? quienOfrece : "costo del servicio" })
16527
- ] }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "px-chat-price-neg__by", children: "A\xFAn no hay una oferta. Prop\xF3n un valor." }) }),
16528
- !cerrada && /* @__PURE__ */ jsxRuntime.jsx("div", { className: `px-chat-price-neg__turn${myTurn ? " is-mine" : ""}`, children: myTurn ? canPropose ? "Es tu turno: acepta o contraprop\xF3n." : "Es tu turno: acepta o rechaza." : "Esperando la respuesta de la otra parte\u2026" }),
16529
- !cerrada && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-chat-price-neg__actions", children: [
16530
- actions.map((a) => {
16531
- const gated = TURN_GATED.has(a.key) && !myTurn;
16532
- const noOffer = a.key === "accept_price" && !hasOffer;
16533
- const disabled = gated || noOffer;
16534
- return /* @__PURE__ */ jsxRuntime.jsx(
16535
- "button",
16536
- {
16537
- type: "button",
16538
- className: `px-chat-price-neg__action${a.intent === "danger" ? " is-danger" : a.key === "accept_price" ? " is-primary" : ""}`,
16539
- disabled,
16540
- title: gated ? "Esperando la respuesta de la otra parte" : void 0,
16541
- onClick: () => a.form ? setActiveAction({ action: a, row }) : crud.runEndpoints(a.endpoints ?? [a.endpoint], { ...row, id: row[config.idField] }),
16542
- children: a.label
16543
- },
16544
- a.key
16545
- );
16546
- }),
16547
- actions.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-chat-price-neg__hint", children: "Sin acciones disponibles." })
16548
- ] })
16549
- ] }),
16550
- activeAction && /* @__PURE__ */ jsxRuntime.jsx(
16551
- ActionFormDrawer,
16552
- {
16553
- action: activeAction.action,
16554
- row: activeAction.row,
16555
- idField: config.idField,
16556
- eventBus,
16557
- onExecute: (ctx) => crud.runEndpoints(activeAction.action.endpoints ?? [activeAction.action.endpoint], ctx),
16558
- onClose: () => setActiveAction(null)
16559
- }
16560
- )
16561
- ] });
16562
- }
16563
-
16564
16465
  function MapViewChat({ component, eventBus }) {
16565
16466
  const { googleMapsApiKey } = useChatConfig();
16566
16467
  const props = component.props ?? {};
@@ -16775,30 +16676,6 @@ const ServicesMap = ({ config, eventBus, apiKey, filter, fill }) => {
16775
16676
  };
16776
16677
  ServicesMap.displayName = "ServicesMap";
16777
16678
 
16778
- function ServicesMapChat({ component, eventBus }) {
16779
- const { resolveModuleConfig, googleMapsApiKey } = useChatConfig();
16780
- const props = component.props ?? {};
16781
- const top = component;
16782
- const pick = (key) => props[key] !== void 0 ? props[key] : top[key];
16783
- const moduleKey = pick("module");
16784
- let config;
16785
- if (typeof moduleKey === "string" && resolveModuleConfig) {
16786
- config = resolveModuleConfig(moduleKey);
16787
- } else if (pick("data")) {
16788
- config = component.props ? props : top;
16789
- }
16790
- if (!config?.data?.list) return null;
16791
- return /* @__PURE__ */ jsxRuntime.jsx(
16792
- ServicesMap,
16793
- {
16794
- config,
16795
- eventBus,
16796
- apiKey: googleMapsApiKey,
16797
- filter: pick("filter")
16798
- }
16799
- );
16800
- }
16801
-
16802
16679
  const CLASS$5 = `${COMPONENT_PREFIX$1}service-shortcuts`;
16803
16680
  const ICONS = {
16804
16681
  map: /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "20", height: "20", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: [
@@ -16875,62 +16752,6 @@ const ServiceShortcuts = ({
16875
16752
  };
16876
16753
  ServiceShortcuts.displayName = "ServiceShortcuts";
16877
16754
 
16878
- const USED_KEY = (messageId) => `px:service_shortcuts:used:${messageId}`;
16879
- function readUsed(messageId) {
16880
- if (!messageId) return void 0;
16881
- try {
16882
- return localStorage.getItem(USED_KEY(messageId)) ?? void 0;
16883
- } catch {
16884
- return void 0;
16885
- }
16886
- }
16887
- const DEFAULTS = {
16888
- map: { id: "map", label: "Ver en el mapa", hint: "D\xF3nde est\xE1n ubicados", route: "/mapa", icon: "map" },
16889
- list: { id: "list", label: "Ver la lista", hint: "Gestionar y filtrar", route: "/servicios", icon: "list" },
16890
- // SPEC-030 — las dos puertas de quien llega por el enlace público y no sabe qué escribir.
16891
- // No navegan: dicen por él lo que tendría que teclear, y el agente responde con el formulario
16892
- // que toque. Así el componente no necesita saber qué formulario es cada cosa.
16893
- request: {
16894
- id: "request",
16895
- label: "Solicitar una gr\xFAa",
16896
- hint: "Pedir el servicio ahora",
16897
- prompt: "Quiero solicitar una gr\xFAa",
16898
- icon: "tow"
16899
- },
16900
- check: {
16901
- id: "check",
16902
- label: "Consultar mi servicio",
16903
- hint: "Ya ped\xED una gr\xFAa antes",
16904
- prompt: "Quiero consultar el servicio que ya ped\xED",
16905
- icon: "search"
16906
- }
16907
- };
16908
- function ServiceShortcutsChat({ component, eventBus, assistantMessageId }) {
16909
- const [elegido, setElegido] = React.useState(() => readUsed(assistantMessageId));
16910
- const props = component.props ?? {};
16911
- const top = component;
16912
- const pick = (key) => props[key] !== void 0 ? props[key] : top[key];
16913
- const recordar = (id) => {
16914
- setElegido(id);
16915
- if (!assistantMessageId) return;
16916
- try {
16917
- localStorage.setItem(USED_KEY(assistantMessageId), id);
16918
- } catch {
16919
- }
16920
- };
16921
- const custom = pick("options");
16922
- const options = custom?.length ? custom : (pick("show") ?? ["map", "list"]).map((k) => DEFAULTS[k]).filter(Boolean);
16923
- return /* @__PURE__ */ jsxRuntime.jsx(
16924
- ServiceShortcuts,
16925
- {
16926
- options,
16927
- eventBus,
16928
- selectedId: elegido,
16929
- onSelect: recordar
16930
- }
16931
- );
16932
- }
16933
-
16934
16755
  const DATE_CHIPS = [
16935
16756
  { key: "todo", label: "Todo" },
16936
16757
  { key: "hoy", label: "Hoy" },
@@ -17594,16 +17415,39 @@ const COMPONENT_MAP = {
17594
17415
  action_menu: ActionMenu,
17595
17416
  reactive_crud: ReactiveCrudChat,
17596
17417
  reactive_crud_item: ReactiveCrudItemChat,
17597
- price_negotiation: PriceNegotiationChat,
17598
17418
  chat_navigator: ChatNavigatorChat,
17599
17419
  user_tools: UserToolsChat,
17600
- map_view: MapViewChat,
17601
- services_map: ServicesMapChat,
17602
- service_shortcuts: ServiceShortcutsChat
17603
- };
17420
+ map_view: MapViewChat
17421
+ // SPEC-115 — `price_negotiation`, `services_map` y `service_shortcuts` salieron de aquí: son del flujo del
17422
+ // solicitante de grúas, no primitivos de diseño. Los registra el host (towing-web) con
17423
+ // `registerChatComponents`. Los componentes de presentación (ServicesMap, ServiceShortcuts)
17424
+ // SÍ se quedan y siguen exportándose: lo que se fue es su adaptador al chat.
17425
+ };
17426
+ const HOST_COMPONENTS = {};
17427
+ function normalizar(e) {
17428
+ return typeof e === "function" ? { render: e } : e;
17429
+ }
17430
+ function registerChatComponents(comps) {
17431
+ for (const [tipo, entrada] of Object.entries(comps)) {
17432
+ HOST_COMPONENTS[tipo] = normalizar(entrada);
17433
+ }
17434
+ }
17435
+ function clearChatComponents() {
17436
+ for (const tipo of Object.keys(HOST_COMPONENTS)) delete HOST_COMPONENTS[tipo];
17437
+ }
17438
+ function esPersistente(tipo) {
17439
+ const h = HOST_COMPONENTS[tipo];
17440
+ if (h) return h.persistent === true;
17441
+ return PERSISTENT_COMPONENTS.has(tipo);
17442
+ }
17443
+ function esDisplayPuro(tipo) {
17444
+ const h = HOST_COMPONENTS[tipo];
17445
+ if (h) return h.pureDisplay === true;
17446
+ return PURE_DISPLAY_COMPONENTS.has(tipo);
17447
+ }
17604
17448
  function renderComponent(props) {
17605
17449
  const { component } = props;
17606
- if (!PERSISTENT_COMPONENTS.has(component.type) && !PURE_DISPLAY_COMPONENTS.has(component.type)) {
17450
+ if (!esPersistente(component.type) && !esDisplayPuro(component.type)) {
17607
17451
  if (component.status) {
17608
17452
  if (TERMINAL_STATUS.has(component.status)) {
17609
17453
  const policy = component.visibility_policy ?? "hide_on_terminal";
@@ -17616,7 +17460,7 @@ function renderComponent(props) {
17616
17460
  return null;
17617
17461
  }
17618
17462
  }
17619
- const Component = COMPONENT_MAP[component.type];
17463
+ const Component = HOST_COMPONENTS[component.type]?.render ?? COMPONENT_MAP[component.type];
17620
17464
  if (!Component) return null;
17621
17465
  return /* @__PURE__ */ jsxRuntime.jsx(Component, { ...props });
17622
17466
  }
@@ -24754,6 +24598,7 @@ function buildBreadcrumbPath(items, targetKey, currentPath = []) {
24754
24598
  return [];
24755
24599
  }
24756
24600
 
24601
+ exports.ActionFormDrawer = ActionFormDrawer;
24757
24602
  exports.BottomSheet = BottomSheet;
24758
24603
  exports.CHAT_CONFIG_DEFAULTS = CHAT_CONFIG_DEFAULTS;
24759
24604
  exports.CHAT_EVENT = CHAT_EVENT;
@@ -24852,11 +24697,18 @@ exports.ServicesMap = ServicesMap;
24852
24697
  exports.SessionExpiryPrompt = SessionExpiryPrompt;
24853
24698
  exports.UserTools = UserTools;
24854
24699
  exports.chatEventBus = chatEventBus;
24700
+ exports.clearChatComponents = clearChatComponents;
24855
24701
  exports.createDeepPropertySubscriber = createDeepPropertySubscriber;
24856
24702
  exports.createEventBus = createEventBus;
24857
24703
  exports.createStore = createStore;
24858
24704
  exports.createStoreMerger = createStoreMerger;
24859
24705
  exports.deepMerge = deepMerge;
24706
+ exports.disabledReasonFor = disabledReasonFor;
24860
24707
  exports.getLastFleetSnapshot = getLastFleetSnapshot;
24708
+ exports.matchesDisabledWhen = matchesDisabledWhen;
24709
+ exports.matchesDoneWhen = matchesDoneWhen;
24710
+ exports.matchesVisibleWhen = matchesVisibleWhen;
24711
+ exports.registerChatComponents = registerChatComponents;
24861
24712
  exports.setLastFleetSnapshot = setLastFleetSnapshot;
24862
24713
  exports.useChatConfig = useChatConfig;
24714
+ exports.useReactiveCrud = useReactiveCrud;