@classytic/pos-ui 0.2.0 → 1.2.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.
Files changed (87) hide show
  1. package/LICENSE +75 -0
  2. package/dist/components/CartSidebar.d.ts +56 -0
  3. package/dist/components/CartSidebar.js +10 -9
  4. package/dist/components/PosTopBar.d.ts +19 -0
  5. package/dist/components/PosTopBar.js +4 -4
  6. package/dist/components/PrinterSettingsDialog.d.ts +8 -0
  7. package/dist/components/PrinterSettingsDialog.js +506 -20
  8. package/dist/components/ReceiptDeliveryDialog.d.ts +11 -0
  9. package/dist/components/ReceiptDeliveryDialog.js +98 -0
  10. package/dist/components/ReceiptReprintDialog.d.ts +10 -0
  11. package/dist/components/ReceiptReprintDialog.js +49 -22
  12. package/dist/components/index.d.ts +6 -0
  13. package/dist/components/index.js +7 -0
  14. package/dist/dashboard/components/CustomerLookupDialog.js +108 -90
  15. package/dist/dashboard/components/CustomerQuickAddDialog.js +3 -1
  16. package/dist/dashboard/components/DeliveryPanel.js +134 -0
  17. package/dist/dashboard/components/ProductCard.js +17 -7
  18. package/dist/dashboard/components/ProductsPanel.js +4 -4
  19. package/dist/dashboard/components/SplitPaymentPanel.js +5 -5
  20. package/dist/dashboard/components/VariantSelectorDialog.js +53 -11
  21. package/dist/dashboard/components/cart/AddChargeDialog.js +3 -2
  22. package/dist/dashboard/components/cart/CartItems.js +5 -5
  23. package/dist/dashboard/components/cart/CartSummary.js +6 -6
  24. package/dist/dashboard/components/cart/CustomerSection.js +3 -3
  25. package/dist/dashboard/components/cart/DiscountSection.js +4 -3
  26. package/dist/dashboard/components/cart/PointsRedemptionSection.js +5 -4
  27. package/dist/dashboard/pos.types.d.ts +32 -0
  28. package/dist/hardware/agent-adapter.js +127 -0
  29. package/dist/hardware/agent-pairing.d.ts +18 -0
  30. package/dist/hardware/agent-pairing.js +63 -0
  31. package/dist/hardware/context.d.ts +1 -5
  32. package/dist/hardware/index.d.ts +4 -3
  33. package/dist/hardware/index.js +3 -2
  34. package/dist/hardware/ports.d.ts +21 -4
  35. package/dist/hardware/tauri-adapter.d.ts +0 -1
  36. package/dist/hardware/tauri-adapter.js +19 -5
  37. package/dist/hardware/web-adapter.d.ts +22 -7
  38. package/dist/hardware/web-adapter.js +56 -14
  39. package/dist/hooks/branch-scoped-key.js +64 -0
  40. package/dist/hooks/index.d.ts +6 -0
  41. package/dist/hooks/index.js +7 -0
  42. package/dist/hooks/sale-attempt.js +62 -0
  43. package/dist/hooks/useManagerAuth.js +9 -1
  44. package/dist/hooks/usePosCart.d.ts +55 -0
  45. package/dist/hooks/usePosCart.js +224 -117
  46. package/dist/hooks/usePosCustomer.d.ts +31 -0
  47. package/dist/hooks/usePosCustomer.js +32 -78
  48. package/dist/hooks/usePosDelivery.d.ts +28 -0
  49. package/dist/hooks/usePosDelivery.js +133 -0
  50. package/dist/hooks/usePosMultiOrder.d.ts +22 -0
  51. package/dist/hooks/usePosMultiOrder.js +14 -4
  52. package/dist/hooks/usePosPayment.d.ts +22 -0
  53. package/dist/lib/delivery-payload.js +83 -0
  54. package/dist/lib/money.js +96 -23
  55. package/dist/node_modules/react-hook-form/dist/index.esm.js +468 -332
  56. package/dist/runtime/auth-port.d.ts +1 -5
  57. package/dist/runtime/branch-port.d.ts +1 -5
  58. package/dist/runtime/config.d.ts +43 -6
  59. package/dist/runtime/config.js +18 -1
  60. package/dist/runtime/index.d.ts +2 -2
  61. package/dist/runtime/index.js +2 -2
  62. package/dist/screens/OrderHistoryDrawer.d.ts +8 -0
  63. package/dist/screens/OrderHistoryDrawer.js +15 -15
  64. package/dist/screens/ParkedOrdersDrawer.d.ts +12 -0
  65. package/dist/screens/ParkedOrdersDrawer.js +3 -3
  66. package/dist/screens/PaymentScreen.d.ts +4 -0
  67. package/dist/screens/PaymentScreen.js +194 -33
  68. package/dist/screens/ProductScreen.d.ts +4 -0
  69. package/dist/screens/ProductScreen.js +13 -10
  70. package/dist/screens/ReceiptScreen.d.ts +4 -0
  71. package/dist/screens/ReceiptScreen.js +96 -72
  72. package/dist/screens/ShiftCloseScreen.d.ts +4 -0
  73. package/dist/screens/ShiftCloseScreen.js +18 -15
  74. package/dist/screens/ShiftOpenScreen.d.ts +4 -0
  75. package/dist/screens/ShiftOpenScreen.js +75 -19
  76. package/dist/screens/index.d.ts +8 -0
  77. package/dist/screens/index.js +9 -0
  78. package/dist/shell/index.d.ts +2 -0
  79. package/dist/shell/pos-shell.d.ts +41 -8
  80. package/dist/shell/pos-shell.js +25 -18
  81. package/dist/state/index.d.ts +3 -0
  82. package/dist/state/index.js +4 -0
  83. package/dist/state/pos-context.d.ts +13 -0
  84. package/dist/state/pos-state.d.ts +49 -0
  85. package/dist/state/pos-state.js +6 -7
  86. package/dist/utils/pos-helpers.js +137 -34
  87. package/package.json +112 -92
package/LICENSE ADDED
@@ -0,0 +1,75 @@
1
+ Classytic Source-Available License (Community & Commercial), Version 1.0
2
+
3
+ Copyright (c) 2026 Classytic LLC. All rights reserved.
4
+
5
+ This software is source-available, not open source. Please read this License
6
+ before using it.
7
+
8
+ 1. DEFINITIONS
9
+ "Software" means the contents of this package and any accompanying source
10
+ code, object code, or documentation, in any form.
11
+ "Licensor" means Classytic LLC, a limited liability company organized in the
12
+ United States.
13
+ "You" means the individual or legal entity exercising rights under this
14
+ License.
15
+ "Evaluation Use" means use for evaluation, development, testing,
16
+ experimentation, or internal non-commercial purposes only.
17
+ "Production Use" means any use of the Software that is live, commercial,
18
+ revenue-generating, or customer-facing, or any use other than Evaluation Use.
19
+ "Commercial License" means a separate written agreement executed with
20
+ Licensor that grants Production Use rights.
21
+
22
+ 2. OWNERSHIP
23
+ The Software is licensed, not sold. Licensor retains all right, title, and
24
+ interest in and to the Software, including all intellectual property rights.
25
+ All rights not expressly granted in this License are reserved by Licensor.
26
+
27
+ 3. EVALUATION GRANT
28
+ Subject to Your compliance with this License, Licensor grants You a
29
+ worldwide, royalty-free, non-exclusive, non-transferable, revocable license
30
+ to download, install, run, and modify the Software solely for Evaluation Use.
31
+
32
+ 4. PRODUCTION USE REQUIRES A COMMERCIAL LICENSE
33
+ Production Use of the Software is NOT permitted under this License and
34
+ requires a Commercial License from Licensor. A Commercial License may be
35
+ granted at Licensor's discretion, with or without a fee, and may confer
36
+ perpetual, irrevocable, and transferable Production Use rights as set out in
37
+ that agreement. Contact licensing@classytic.com to obtain one.
38
+
39
+ 5. RESTRICTIONS
40
+ You may not:
41
+ (a) make any Production Use of the Software without a Commercial License;
42
+ (b) redistribute, resell, rent, sublicense, or otherwise make the Software
43
+ (in whole or in part, original or modified) available to third parties as
44
+ a stand-alone product, framework, library, or hosted/managed service that
45
+ competes with the Software or with Licensor;
46
+ (c) remove, obscure, or alter any copyright, license, or attribution notice.
47
+
48
+ 6. FEEDBACK AND CONTRIBUTIONS
49
+ Any feedback, suggestions, or contributions You provide relating to the
50
+ Software may be used by Licensor for any purpose without obligation to You.
51
+
52
+ 7. TERMINATION
53
+ This License and the Evaluation Grant terminate automatically if You breach
54
+ any term. Upon termination You must cease all use of the Software and destroy
55
+ all copies in Your possession. Rights under a Commercial License are governed
56
+ by that agreement's own terms and survive termination of this License to the
57
+ extent stated there.
58
+
59
+ 8. DISCLAIMER OF WARRANTY
60
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62
+ FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT.
63
+
64
+ 9. LIMITATION OF LIABILITY
65
+ TO THE MAXIMUM EXTENT PERMITTED BY LAW, IN NO EVENT SHALL LICENSOR BE LIABLE
66
+ FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
67
+ TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE
68
+ OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
69
+
70
+ 10. GOVERNING LAW
71
+ This License is governed by the laws of the State of Delaware, United States,
72
+ without regard to its conflict-of-laws principles. (Adjust to Your LLC's state
73
+ of formation.)
74
+
75
+ For commercial licensing, contact: licensing@classytic.com
@@ -0,0 +1,56 @@
1
+ import { UsePosCartReturn } from "../hooks/usePosCart.js";
2
+ import { UsePosCustomerReturn } from "../hooks/usePosCustomer.js";
3
+ //#region src/components/CartSidebar.d.ts
4
+ interface CartSidebarProps {
5
+ cart: UsePosCartReturn;
6
+ customer: UsePosCustomerReturn;
7
+ /**
8
+ * `loyalty.membership` config. `pointValueMinor` is integer MINOR units per
9
+ * point (loyalty 0.6.0); the legacy `pointsPerBdt` it replaced was the
10
+ * RECIPROCAL quantity and the server no longer emits it.
11
+ */
12
+ membership: {
13
+ enabled?: boolean;
14
+ redemption?: {
15
+ enabled?: boolean;
16
+ minRedeemPoints?: number;
17
+ pointValueMinor?: number;
18
+ };
19
+ } | null | undefined;
20
+ orderTotals: {
21
+ subtotal: number;
22
+ manualDiscount: number;
23
+ tierDiscount: number;
24
+ tierName: string | null;
25
+ redemptionDiscount: number;
26
+ total: number;
27
+ pointsToEarn: number;
28
+ pointsRedeemed: number;
29
+ redemptionError: string | null;
30
+ maxAllowedPoints: number;
31
+ };
32
+ discountAuth: {
33
+ isAuthorized: boolean;
34
+ authorizedBy: {
35
+ name: string;
36
+ } | null;
37
+ clearAuth: () => void;
38
+ };
39
+ onCheckout: () => void;
40
+ onRequestDiscountAuth: () => void;
41
+ onClearDiscountAuth: () => void;
42
+ /** Park-current-sale handler (F6). Disabled when cart is empty or
43
+ * the parked-orders store is full. */
44
+ onParkSale?: () => void;
45
+ /** Open the parked-sales drawer (F7). Always available so the cashier
46
+ * can review/restore pending holds. */
47
+ onOpenParked?: () => void;
48
+ /** Number of currently-parked sales — drives the badge on the
49
+ * "Parked" button so the cashier knows there are slots to revisit. */
50
+ parkedCount?: number;
51
+ /** Whether the parked-orders store has room for one more (≤ MAX). */
52
+ canPark?: boolean;
53
+ }
54
+ declare function CartSidebar({ cart, customer, membership, orderTotals, discountAuth, onCheckout, onRequestDiscountAuth, onClearDiscountAuth, onParkSale, onOpenParked, parkedCount, canPark }: CartSidebarProps): import("react").JSX.Element;
55
+ //#endregion
56
+ export { CartSidebar };
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
 
3
- import { formatBdt } from "../lib/money.js";
3
+ import { formatMajor } from "../lib/money.js";
4
4
  import { getReadableTextColor, getTierColor } from "../lib/loyalty.js";
5
5
  import { CartItems } from "../dashboard/components/cart/CartItems.js";
6
6
  import { CartSummary } from "../dashboard/components/cart/CartSummary.js";
@@ -63,7 +63,7 @@ function CartSidebar({ cart, customer, membership, orderTotals, discountAuth, on
63
63
  pointsBalance: customer.selectedCustomer?.membership?.points?.current ?? 0,
64
64
  minRedeemPoints: membership?.redemption?.minRedeemPoints ?? 0,
65
65
  maxRedeemPoints: Math.min(orderTotals.maxAllowedPoints, customer.selectedCustomer?.membership?.points?.current ?? 0),
66
- pointsPerBdt: membership?.redemption?.pointsPerBdt ?? 1,
66
+ pointValueMinor: membership?.redemption?.pointValueMinor,
67
67
  estimatedDiscount: orderTotals.redemptionDiscount,
68
68
  error: orderTotals.redemptionError
69
69
  }), [
@@ -100,11 +100,11 @@ function CartSidebar({ cart, customer, membership, orderTotals, discountAuth, on
100
100
  onClick: onOpenParked,
101
101
  "aria-label": `Parked sales (${parkedCount})`,
102
102
  children: [
103
- /* @__PURE__ */ jsx(Inbox, { className: "h-3.5 w-3.5 mr-1" }),
103
+ /* @__PURE__ */ jsx(Inbox, { className: "h-3.5 w-3.5 me-1" }),
104
104
  "Parked",
105
105
  parkedCount > 0 && /* @__PURE__ */ jsx(Badge, {
106
106
  variant: "secondary",
107
- className: "ml-1.5 h-4 px-1.5 text-[10px]",
107
+ className: "ms-1.5 h-4 px-1.5 text-[10px]",
108
108
  children: parkedCount
109
109
  })
110
110
  ]
@@ -116,14 +116,14 @@ function CartSidebar({ cart, customer, membership, orderTotals, discountAuth, on
116
116
  onClick: onParkSale,
117
117
  disabled: !canPark,
118
118
  title: canPark ? "Park sale (F6)" : "Max 5 parked — resume one first",
119
- children: [/* @__PURE__ */ jsx(PauseCircle, { className: "h-3.5 w-3.5 mr-1" }), "Park"]
119
+ children: [/* @__PURE__ */ jsx(PauseCircle, { className: "h-3.5 w-3.5 me-1" }), "Park"]
120
120
  }),
121
121
  !isEmpty && /* @__PURE__ */ jsxs(Button, {
122
122
  variant: "ghost",
123
123
  size: "sm",
124
124
  className: "h-7 text-xs text-destructive",
125
125
  onClick: cart.clearCart,
126
- children: [/* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5 mr-1" }), "Clear"]
126
+ children: [/* @__PURE__ */ jsx(Trash2, { className: "h-3.5 w-3.5 me-1" }), "Clear"]
127
127
  })
128
128
  ]
129
129
  })]
@@ -195,7 +195,7 @@ function CartSidebar({ cart, customer, membership, orderTotals, discountAuth, on
195
195
  pointsBalance: redemption.pointsBalance,
196
196
  minRedeemPoints: redemption.minRedeemPoints,
197
197
  maxRedeemPoints: redemption.maxRedeemPoints,
198
- pointsPerBdt: redemption.pointsPerBdt,
198
+ pointValueMinor: redemption.pointValueMinor,
199
199
  estimatedDiscount: redemption.estimatedDiscount,
200
200
  error: redemption.error,
201
201
  value: cart.pointsToRedeemInput,
@@ -208,10 +208,11 @@ function CartSidebar({ cart, customer, membership, orderTotals, discountAuth, on
208
208
  }),
209
209
  !isEmpty && /* @__PURE__ */ jsx("div", {
210
210
  className: "px-4 py-3 border-t bg-card",
211
- children: /* @__PURE__ */ jsxs(Button, {
211
+ children: /* @__PURE__ */ jsx(Button, {
212
212
  className: "w-full h-12 text-base font-semibold",
213
213
  onClick: onCheckout,
214
- children: ["Checkout ", formatBdt(orderTotals.total)]
214
+ disabled: !cart.ready,
215
+ children: cart.ready ? `Checkout ${formatMajor(orderTotals.total)}` : "Preparing register…"
215
216
  })
216
217
  })
217
218
  ]
@@ -0,0 +1,19 @@
1
+ //#region src/components/PosTopBar.d.ts
2
+ interface PosTopBarProps {
3
+ userName?: string;
4
+ /**
5
+ * Host-supplied actions rendered before the built-in ones — a gym's
6
+ * "Find member" / "Day pass", a hotel's "Charge to room". Keeps a vertical
7
+ * out of this component's business.
8
+ */
9
+ actions?: import("react").ReactNode;
10
+ onNewSale?: () => void;
11
+ onOpenHistory?: () => void;
12
+ /** Open the keyboard-shortcuts help dialog (also bound to `?`). */
13
+ onOpenHelp?: () => void;
14
+ /** Open the printer-settings dialog (host/port + test connection). */
15
+ onOpenPrinterSettings?: () => void;
16
+ }
17
+ declare function PosTopBar({ userName, actions, onNewSale, onOpenHistory, onOpenHelp, onOpenPrinterSettings }: PosTopBarProps): import("react").JSX.Element;
18
+ //#endregion
19
+ export { PosTopBar, PosTopBarProps };
@@ -32,7 +32,7 @@ function useClock() {
32
32
  }, []);
33
33
  return time;
34
34
  }
35
- function PosTopBar({ userName, onNewSale, onOpenHistory, onOpenHelp, onOpenPrinterSettings }) {
35
+ function PosTopBar({ userName, actions, onNewSale, onOpenHistory, onOpenHelp, onOpenPrinterSettings }) {
36
36
  const selectedBranch = usePosBranch();
37
37
  const { onNavigate } = usePosRuntime();
38
38
  const { state, dispatch } = usePosContext();
@@ -105,15 +105,15 @@ function PosTopBar({ userName, onNewSale, onOpenHistory, onOpenHelp, onOpenPrint
105
105
  })
106
106
  ]
107
107
  }),
108
- /* @__PURE__ */ jsx("div", {
108
+ /* @__PURE__ */ jsxs("div", {
109
109
  className: "flex-1 flex items-center justify-center gap-1 px-4",
110
- children: state.screen === "products" && onNewSale && /* @__PURE__ */ jsxs(Button, {
110
+ children: [actions, state.screen === "products" && onNewSale && /* @__PURE__ */ jsxs(Button, {
111
111
  variant: "ghost",
112
112
  size: "sm",
113
113
  onClick: onNewSale,
114
114
  className: "h-8 text-xs gap-1",
115
115
  children: [/* @__PURE__ */ jsx(Plus, { className: "h-3.5 w-3.5" }), "New Sale"]
116
- })
116
+ })]
117
117
  }),
118
118
  /* @__PURE__ */ jsxs("div", {
119
119
  className: "flex items-center gap-3 shrink-0",
@@ -0,0 +1,8 @@
1
+ //#region src/components/PrinterSettingsDialog.d.ts
2
+ interface PrinterSettingsDialogProps {
3
+ open: boolean;
4
+ onOpenChange: (open: boolean) => void;
5
+ }
6
+ declare function PrinterSettingsDialog({ open, onOpenChange }: PrinterSettingsDialogProps): import("react").JSX.Element;
7
+ //#endregion
8
+ export { PrinterSettingsDialog };