@fayz-ai/pos 0.23.0 → 0.23.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
@@ -1,7 +1,7 @@
1
1
  import { haptic, createKeymap, directionOf, moveFocus } from '@fayz-ai/core/interaction';
2
2
  export { comboOf, createKeymap, haptic, setHapticsEnabled } from '@fayz-ai/core/interaction';
3
3
  import { forwardRef, memo, useState, useRef, useCallback, useEffect, useMemo, useReducer, Fragment as Fragment$1 } from 'react';
4
- import { UserPlus, X, Check, Phone, User, Receipt, RotateCcw, FileCheck, FileWarning, ChevronDown, Pencil, ChevronLeft, ChevronRight, Plus, ChevronUp, ChefHat, AlertTriangle, Printer, Percent, QrCode, CreditCard, Banknote, Trash2, Clock, Minus, Bike, PackageCheck, CheckCheck, Package, MapPin, ShieldCheck, Keyboard, CalendarClock, Users, UserRound, Search, Utensils, BellRing, UserX, UserCheck, Delete, UtensilsCrossed, Info, ClipboardList, LayoutGrid, ShoppingBag, ConciergeBell, Map as Map$1, Settings2, Square, Circle, PenLine, MoreHorizontal, Store, Tag, Star, Ticket, Ban, Loader2, ArrowLeftRight, Gift, UserMinus, CheckCircle2, Crosshair, Unlink, MousePointerClick, PencilRuler, MapPinOff, Eye, EyeOff, Undo2, TriangleAlert, ArrowRight, Pizza, Wheat, Sandwich, IceCreamCone, CakeSlice, Coffee, Croissant, CupSoda, Salad, Beef, Wine, GlassWater, Soup, Fish, Wrench, CalendarCheck } from 'lucide-react';
4
+ import { UserPlus, X, Check, Phone, User, Receipt, RotateCcw, FileCheck, FileWarning, ChevronDown, Pencil, ChevronLeft, ChevronRight, Plus, ChevronUp, ChefHat, AlertTriangle, Printer, Percent, QrCode, CreditCard, Banknote, Trash2, Clock, Minus, Bike, History, PackageCheck, CheckCheck, Package, MapPin, ShieldCheck, Keyboard, CalendarClock, Users, UserRound, Search, Utensils, BellRing, UserX, UserCheck, Delete, UtensilsCrossed, Info, ClipboardList, LayoutGrid, ShoppingBag, ConciergeBell, Map as Map$1, Settings2, Square, Circle, PenLine, MoreHorizontal, Store, Tag, Star, Ticket, Ban, ArrowLeftRight, Gift, UserMinus, CheckCircle2, Crosshair, Unlink, MousePointerClick, PencilRuler, MapPinOff, Eye, EyeOff, Undo2, TriangleAlert, ArrowRight, Pizza, Wheat, Sandwich, IceCreamCone, CakeSlice, Coffee, Croissant, CupSoda, Salad, Beef, Wine, GlassWater, Soup, Fish, Wrench, CalendarCheck } from 'lucide-react';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
6
  import { describeError, channelOfOrder } from '@fayz-ai/core';
7
7
  import { createPortal } from 'react-dom';
@@ -4869,7 +4869,7 @@ function lateness(p, now) {
4869
4869
  return Math.floor((now - new Date(p.dueAt).getTime()) / 6e4);
4870
4870
  }
4871
4871
  var GHOST_MS = 300;
4872
- function DeliveryBoard({ orders, activeId, onSelect, now, channelsConnected }) {
4872
+ function DeliveryBoard({ orders, activeId, onSelect, now, channelsConnected, historyOpen, onToggleHistory }) {
4873
4873
  const seen = useRef({});
4874
4874
  const [ghosts, setGhosts] = useState([]);
4875
4875
  useEffect(() => {
@@ -4897,7 +4897,14 @@ function DeliveryBoard({ orders, activeId, onSelect, now, channelsConnected }) {
4897
4897
  Icon: Bike
4898
4898
  }
4899
4899
  ),
4900
- /* @__PURE__ */ jsx("p", { className: "pos-board__note", children: DELIVERED_LINGER_NOTE }),
4900
+ /* @__PURE__ */ jsxs("div", { className: "pos-board__bar", children: [
4901
+ /* @__PURE__ */ jsx("p", { className: "pos-board__note", children: DELIVERED_LINGER_NOTE }),
4902
+ onToggleHistory && /* @__PURE__ */ jsxs(PosButton, { className: "pos-pill", "aria-pressed": !!historyOpen, onClick: onToggleHistory, children: [
4903
+ /* @__PURE__ */ jsx(History, { size: 14 }),
4904
+ " ",
4905
+ historyOpen ? "Ocultar hist\xF3rico" : "Hist\xF3rico do dia"
4906
+ ] })
4907
+ ] }),
4901
4908
  /* @__PURE__ */ jsx("div", { className: "pos-board", children: DELIVERY_COLUMNS.map(({ name, states, tone }) => {
4902
4909
  const Icon = ICONE[name] ?? Clock;
4903
4910
  const column = orders.filter((o) => stillOnBoard(o, now)).filter((o) => states.includes(deliveryStatus(o.dispatch)));
@@ -4997,6 +5004,7 @@ function DispatchRail({
4997
5004
  totals,
4998
5005
  onAdvance,
4999
5006
  onCancel,
5007
+ onCloseDetails,
5000
5008
  now,
5001
5009
  open,
5002
5010
  containerRef,
@@ -5016,7 +5024,18 @@ function DispatchRail({
5016
5024
  /* @__PURE__ */ jsxs("header", { className: "pos-tkt", children: [
5017
5025
  /* @__PURE__ */ jsxs("div", { className: "pos-tkt__row", children: [
5018
5026
  /* @__PURE__ */ jsx("span", { className: "pos-t-xl", children: order.label }),
5019
- /* @__PURE__ */ jsx("span", { className: "pos-badge", "data-status": status === "out" || status === "dispatched" ? "bill_requested" : "occupied", children: DISPATCH_LABEL[status] })
5027
+ /* @__PURE__ */ jsx("span", { className: "pos-badge", "data-status": status === "out" || status === "dispatched" ? "bill_requested" : "occupied", children: DISPATCH_LABEL[status] }),
5028
+ onCloseDetails && /* @__PURE__ */ jsx(
5029
+ PosButton,
5030
+ {
5031
+ className: "pos-icon-btn",
5032
+ style: { marginLeft: "auto" },
5033
+ onClick: onCloseDetails,
5034
+ "aria-label": "Fechar detalhes",
5035
+ title: "Fechar detalhes \xB7 Esc",
5036
+ children: /* @__PURE__ */ jsx(X, { size: 18 })
5037
+ }
5038
+ )
5020
5039
  ] }),
5021
5040
  /* @__PURE__ */ jsx("div", { className: "pos-tkt__sub", children: [order.channel, order.customerName].filter(Boolean).join(" \xB7 ") })
5022
5041
  ] }),
@@ -7730,6 +7749,10 @@ function PosScreen({
7730
7749
  return;
7731
7750
  }
7732
7751
  if (event.key === "Escape") {
7752
+ if (activeKindRef.current === "delivery") {
7753
+ closeDetailsRef.current();
7754
+ return;
7755
+ }
7733
7756
  commandRef.current?.focus();
7734
7757
  return;
7735
7758
  }
@@ -7782,6 +7805,10 @@ function PosScreen({
7782
7805
  return { ...p, itemCount: counts[p.id] ?? p.itemCount, totalCents: totalCents || p.totalCents };
7783
7806
  }), [positions, opened, dispatched, settled, book, counts, config.serviceChargePercent, minhas]);
7784
7807
  const activePosition = livePositions.find((p) => p.id === activePositionId);
7808
+ const activeIdRef = useRef(activePositionId);
7809
+ activeIdRef.current = activePositionId;
7810
+ const activeKindRef = useRef(activePosition?.kind);
7811
+ activeKindRef.current = activePosition?.kind;
7785
7812
  const trocarCanal = useCallback((id) => {
7786
7813
  if (channelSwitchDropsPosition(
7787
7814
  { menuId, activeKind: activePosition?.kind },
@@ -7805,8 +7832,20 @@ function PosScreen({
7805
7832
  ),
7806
7833
  [closedTickets, canalMarcado, menu?.view]
7807
7834
  );
7835
+ const [deliveryHistory, setDeliveryHistory] = useState(false);
7836
+ const closeDetailsRef = useRef(() => {
7837
+ });
7838
+ closeDetailsRef.current = () => {
7839
+ setActivePositionId(void 0);
7840
+ setSelectedLineId(void 0);
7841
+ setRailOpen(false);
7842
+ };
7808
7843
  const escapeRef = useRef(() => false);
7809
7844
  escapeRef.current = () => {
7845
+ if (activePosition?.kind === "delivery") {
7846
+ closeDetailsRef.current();
7847
+ return true;
7848
+ }
7810
7849
  if (railOpen) {
7811
7850
  setRailOpen(false);
7812
7851
  return true;
@@ -7905,6 +7944,10 @@ function PosScreen({
7905
7944
  return;
7906
7945
  }
7907
7946
  if (seatingRef.current) return;
7947
+ if (p.kind === "delivery" && p.id === activeIdRef.current) {
7948
+ closeDetailsRef.current();
7949
+ return;
7950
+ }
7908
7951
  setActivePositionId(p.id);
7909
7952
  onActivatePosition?.(p.id);
7910
7953
  setRailOpen(true);
@@ -8341,7 +8384,7 @@ function PosScreen({
8341
8384
  style,
8342
8385
  "data-cart-open": railOpen || void 0,
8343
8386
  children: [
8344
- /* @__PURE__ */ jsxs("div", { className: "pos-body", children: [
8387
+ /* @__PURE__ */ jsxs("div", { className: "pos-body", "data-details": menu?.view === "list" && !activePosition && !deliveryHistory ? "closed" : void 0, children: [
8345
8388
  /* @__PURE__ */ jsxs("nav", { className: "pos-rail", "aria-label": "Navega\xE7\xE3o principal", children: [
8346
8389
  (brandMark || brandName || !railTop) && /* @__PURE__ */ jsxs("div", { className: "pos-brand", children: [
8347
8390
  /* @__PURE__ */ jsx("span", { className: "pos-brand__mark", children: brandMark ?? config.name.slice(0, 1) }),
@@ -8649,7 +8692,9 @@ function PosScreen({
8649
8692
  orders: livePositions.filter((p) => p.kind === "delivery"),
8650
8693
  activeId: activePositionId,
8651
8694
  onSelect: selectPosition,
8652
- now
8695
+ now,
8696
+ historyOpen: deliveryHistory && !activePosition,
8697
+ onToggleHistory: activePosition ? void 0 : () => setDeliveryHistory((v) => !v)
8653
8698
  }
8654
8699
  ),
8655
8700
  menu?.view === "reservations" && /* @__PURE__ */ jsx(
@@ -8975,6 +9020,7 @@ function PosScreen({
8975
9020
  void onDispatch?.(activePosition.id, to);
8976
9021
  },
8977
9022
  onCancel: () => handleAction("cancel_order"),
9023
+ onCloseDetails: () => closeDetailsRef.current(),
8978
9024
  extra: renderDispatchExtra?.(activePosition, ticket)
8979
9025
  }
8980
9026
  ) : /* @__PURE__ */ jsxs(Fragment, { children: [
@@ -10212,7 +10258,6 @@ function MarketplaceCancelSheet({ provider, orderLabel, loadReasons, onConfirm,
10212
10258
  const [chosen, setChosen] = useState(null);
10213
10259
  const [sending, setSending] = useState(false);
10214
10260
  const [attempt, setAttempt] = useState(0);
10215
- const list = useRef(null);
10216
10261
  useEffect(() => {
10217
10262
  let alive = true;
10218
10263
  setFailed(false);
@@ -10227,72 +10272,44 @@ function MarketplaceCancelSheet({ provider, orderLabel, loadReasons, onConfirm,
10227
10272
  };
10228
10273
  }, [loadReasons, attempt]);
10229
10274
  const reason = reasons?.find((r) => r.code === chosen);
10230
- const onKey = (e) => {
10231
- if (!reasons?.length || !["ArrowDown", "ArrowUp", "ArrowRight", "ArrowLeft"].includes(e.key)) return;
10232
- e.preventDefault();
10233
- const at = Math.max(0, reasons.findIndex((r) => r.code === chosen));
10234
- const step = e.key === "ArrowDown" || e.key === "ArrowRight" ? 1 : -1;
10235
- const next = reasons[(at + step + reasons.length) % reasons.length];
10236
- setChosen(next.code);
10237
- list.current?.querySelector(`[data-code="${CSS.escape(next.code)}"]`)?.focus();
10238
- };
10239
10275
  return /* @__PURE__ */ jsxs(PosSheet, { label: "Cancelar pedido", onDismiss: onCancel, children: [
10240
10276
  /* @__PURE__ */ jsxs("div", { className: "pos-sheet__head", children: [
10241
- /* @__PURE__ */ jsxs("div", { className: "pos-mcs__headtext", children: [
10242
- /* @__PURE__ */ jsxs("h2", { className: "pos-sheet__title", children: [
10243
- /* @__PURE__ */ jsx(Ban, { size: 18, strokeWidth: 2.2, "aria-hidden": true }),
10244
- " Cancelar ",
10245
- orderLabel
10246
- ] }),
10247
- /* @__PURE__ */ jsxs("p", { className: "pos-sheet__sub", children: [
10248
- "O ",
10249
- provider,
10250
- " decide o cancelamento. Escolha um dos motivos que ele aceita para este pedido."
10251
- ] })
10277
+ /* @__PURE__ */ jsxs("h2", { className: "pos-sheet__title", children: [
10278
+ /* @__PURE__ */ jsx(Ban, { size: 18, strokeWidth: 2.2, "aria-hidden": true }),
10279
+ " Cancelar ",
10280
+ orderLabel
10252
10281
  ] }),
10253
10282
  /* @__PURE__ */ jsx(PosButton, { className: "pos-sheet__x", onClick: onCancel, "aria-label": "Fechar", children: /* @__PURE__ */ jsx(X, { size: 20 }) })
10254
10283
  ] }),
10255
- /* @__PURE__ */ jsx("div", { className: "pos-sheet__body pos-mcs__body", children: failed ? /* @__PURE__ */ jsxs("div", { className: "pos-mcs__state", role: "alert", children: [
10256
- /* @__PURE__ */ jsxs("p", { children: [
10257
- "N\xE3o foi poss\xEDvel buscar os motivos no ",
10258
- provider,
10259
- "."
10260
- ] }),
10261
- /* @__PURE__ */ jsx(PosButton, { className: "pos-mcs__btn", onClick: () => setAttempt((n) => n + 1), children: "Tentar de novo" })
10262
- ] }) : reasons === null ? /* @__PURE__ */ jsxs("div", { className: "pos-mcs__state", "aria-live": "polite", children: [
10263
- /* @__PURE__ */ jsx(Loader2, { size: 18, className: "pos-mcs__spin", "aria-hidden": true }),
10264
- " Buscando os motivos no ",
10265
- provider,
10266
- "\u2026"
10267
- ] }) : reasons.length === 0 ? /* @__PURE__ */ jsxs("div", { className: "pos-mcs__state", children: [
10284
+ /* @__PURE__ */ jsxs("p", { className: "pos-sheet__sub", children: [
10268
10285
  "O ",
10269
10286
  provider,
10270
- " n\xE3o aceita cancelar este pedido agora."
10271
- ] }) : /* @__PURE__ */ jsx("div", { ref: list, className: "pos-mcs__list", role: "radiogroup", "aria-label": `Motivos do ${provider}`, onKeyDown: onKey, children: reasons.map((r, i) => {
10272
- const on = chosen === r.code;
10273
- return /* @__PURE__ */ jsxs(
10274
- PosButton,
10275
- {
10276
- "data-code": r.code,
10277
- role: "radio",
10278
- "aria-checked": on,
10279
- tabIndex: on || !chosen && i === 0 ? 0 : -1,
10280
- className: `pos-mcs__opt${on ? " is-on" : ""}`,
10281
- onClick: () => setChosen(r.code),
10282
- children: [
10283
- /* @__PURE__ */ jsx("span", { className: "pos-mcs__dot", "aria-hidden": true }),
10284
- /* @__PURE__ */ jsx("span", { children: r.description })
10285
- ]
10286
- },
10287
- r.code
10288
- );
10289
- }) }) }),
10290
- /* @__PURE__ */ jsxs("div", { className: "pos-mcs__foot", children: [
10291
- /* @__PURE__ */ jsx(PosButton, { className: "pos-mcs__btn", onClick: onCancel, disabled: sending, children: "Voltar" }),
10292
- /* @__PURE__ */ jsxs(
10287
+ " decide o cancelamento. Escolha um dos motivos que ele aceita para este pedido."
10288
+ ] }),
10289
+ /* @__PURE__ */ jsx("div", { className: "pos-sheet__body", children: failed ? /* @__PURE__ */ jsx(
10290
+ EmptyState,
10291
+ {
10292
+ title: `N\xE3o foi poss\xEDvel buscar os motivos no ${provider}.`,
10293
+ Icon: Ban,
10294
+ action: { label: "Tentar de novo", onClick: () => setAttempt((n) => n + 1) }
10295
+ }
10296
+ ) : reasons !== null && reasons.length === 0 ? /* @__PURE__ */ jsx(EmptyState, { title: `O ${provider} n\xE3o aceita cancelar este pedido agora.`, Icon: Ban }) : (
10297
+ // The same option rows the modifier and open-table sheets use: a box
10298
+ // that checks and an accent edge on the one chosen.
10299
+ /* @__PURE__ */ jsx("div", { className: "pos-mgroup__opts pos-mgroup__opts--stack", role: "group", "aria-label": `Motivos do ${provider}`, "aria-busy": reasons === null, children: reasons === null ? [0, 1, 2, 3].map((i) => /* @__PURE__ */ jsx("div", { className: "pos-mopt pos-skel", "aria-hidden": true, children: /* @__PURE__ */ jsx("span", { className: "pos-skel__b", style: { width: `${55 + i * 9}%`, height: 14 } }) }, i)) : reasons.map((r) => {
10300
+ const on = chosen === r.code;
10301
+ return /* @__PURE__ */ jsxs(PosButton, { className: "pos-mopt", "aria-pressed": on, onClick: () => setChosen(r.code), children: [
10302
+ /* @__PURE__ */ jsx("span", { className: "pos-mopt__check", children: on && /* @__PURE__ */ jsx(Check, { size: 14, strokeWidth: 3 }) }),
10303
+ /* @__PURE__ */ jsx("span", { className: "pos-mopt__label", children: r.description })
10304
+ ] }, r.code);
10305
+ }) })
10306
+ ) }),
10307
+ /* @__PURE__ */ jsxs("div", { className: "pos-sheet__foot", children: [
10308
+ /* @__PURE__ */ jsx(PosButton, { className: "pos-btn pos-btn--ghost", onClick: onCancel, disabled: sending, children: "Voltar" }),
10309
+ /* @__PURE__ */ jsx(
10293
10310
  PosButton,
10294
10311
  {
10295
- className: "pos-mcs__btn pos-mcs__btn--danger",
10312
+ className: "pos-btn pos-btn--danger",
10296
10313
  disabled: !reason || sending,
10297
10314
  "aria-busy": sending,
10298
10315
  onClick: async () => {
@@ -10304,10 +10321,7 @@ function MarketplaceCancelSheet({ provider, orderLabel, loadReasons, onConfirm,
10304
10321
  setSending(false);
10305
10322
  }
10306
10323
  },
10307
- children: [
10308
- sending && /* @__PURE__ */ jsx(Loader2, { size: 16, className: "pos-mcs__spin", "aria-hidden": true }),
10309
- sending ? "Enviando\u2026" : `Pedir cancelamento ao ${provider}`
10310
- ]
10324
+ children: sending ? "Enviando\u2026" : `Pedir cancelamento ao ${provider}`
10311
10325
  }
10312
10326
  )
10313
10327
  ] })