@tallyui/components 3.0.4 → 3.1.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
@@ -2308,6 +2308,7 @@ function CustomerCard({ doc, traits, className, ...props }) {
2308
2308
  }
2309
2309
 
2310
2310
  // src/customer/customer-select.tsx
2311
+ import { useState as useState6 } from "react";
2311
2312
  import { Pressable as Pressable14, ScrollView as ScrollView6, View as View29 } from "react-native";
2312
2313
  import { Select as Select2 } from "@tallyui/primitives";
2313
2314
  import { useCustomerTraits as useCustomerTraits2 } from "@tallyui/core";
@@ -2325,10 +2326,12 @@ function CustomerSelectView({
2325
2326
  onSelect,
2326
2327
  onSearch,
2327
2328
  placeholder = "Search customers...",
2329
+ showSearch = true,
2328
2330
  className,
2329
2331
  traits,
2330
2332
  ...props
2331
2333
  }) {
2334
+ const [search, setSearch] = useState6("");
2332
2335
  const selectedOption = selected && traits ? { value: traits.getId(selected), label: traits.getName(selected) } : void 0;
2333
2336
  const customerById = /* @__PURE__ */ new Map();
2334
2337
  if (traits) {
@@ -2347,6 +2350,19 @@ function CustomerSelectView({
2347
2350
  onValueChange: handleValueChange,
2348
2351
  defaultOpen: true,
2349
2352
  children: /* @__PURE__ */ jsxs19(VStack, { space: "sm", className: cn56(className), ...props, children: [
2353
+ showSearch && /* @__PURE__ */ jsx59(
2354
+ SearchInput,
2355
+ {
2356
+ value: search,
2357
+ onChangeText: (text) => {
2358
+ setSearch(text);
2359
+ onSearch(text);
2360
+ },
2361
+ placeholder,
2362
+ testID: "customer-select-search",
2363
+ accessibilityLabel: "Search customers"
2364
+ }
2365
+ ),
2350
2366
  selected && traits && /* @__PURE__ */ jsx59(Select2.Trigger, { asChild: true, children: /* @__PURE__ */ jsx59(View29, { className: "rounded-lg border border-primary bg-primary/5 px-3 py-2", children: /* @__PURE__ */ jsx59(CustomerCard, { doc: selected, traits }) }) }),
2351
2367
  customers.length > 0 && /* @__PURE__ */ jsx59(Select2.Content, { asChild: true, forceMount: true, disablePositioningStyle: true, children: /* @__PURE__ */ jsx59(ScrollView6, { className: "max-h-60", children: customers.map((customer, index) => {
2352
2368
  const id = traits?.getId(customer) ?? String(index);
@@ -2431,7 +2447,7 @@ function CustomerOrderHistory({
2431
2447
  }
2432
2448
 
2433
2449
  // src/customer/customer-picker.tsx
2434
- import { useEffect, useRef, useState as useState6 } from "react";
2450
+ import { useEffect, useRef, useState as useState7 } from "react";
2435
2451
  import { Pressable as Pressable16, Text as Text19, TextInput as TextInput7, View as View32 } from "react-native";
2436
2452
  import { customerTraits, CustomerServiceError, ConnectorUnauthorizedError } from "@tallyui/core";
2437
2453
  import { cn as cn59 } from "@tallyui/theme";
@@ -2439,16 +2455,16 @@ import { jsx as jsx62, jsxs as jsxs22 } from "react/jsx-runtime";
2439
2455
  var EMAIL_MAX = 254;
2440
2456
  var EMAIL_SHAPE = /^[^\s@\u0000]+@[^\s@\u0000]+\.[^\s@\u0000]+$/u;
2441
2457
  function CustomerPicker({ search, create, selected, onSelect, onError, online, debounceMs = 250, className }) {
2442
- const [query, setQuery] = useState6("");
2443
- const [customers, setCustomers] = useState6([]);
2444
- const [error, setError] = useState6(null);
2445
- const [showForm, setShowForm] = useState6(false);
2446
- const [creating, setCreating] = useState6(false);
2447
- const [values, setValues] = useState6({ firstName: "", lastName: "", email: "", phone: "", address: "" });
2458
+ const [query, setQuery] = useState7("");
2459
+ const [customers, setCustomers] = useState7([]);
2460
+ const [error, setError] = useState7(null);
2461
+ const [showForm, setShowForm] = useState7(false);
2462
+ const [creating, setCreating] = useState7(false);
2463
+ const [values, setValues] = useState7({ firstName: "", lastName: "", email: "", phone: "", address: "" });
2448
2464
  const sequence = useRef(0);
2449
2465
  const searchRef = useRef(search);
2450
2466
  searchRef.current = search;
2451
- const [noResults, setNoResults] = useState6(false);
2467
+ const [noResults, setNoResults] = useState7(false);
2452
2468
  function handleError(error2) {
2453
2469
  if (error2 instanceof CustomerServiceError) {
2454
2470
  setError(error2.code === "network" ? "Couldn't reach the store. Try again." : error2.code === "server" ? "The store couldn't do that. Try again." : error2.message);
@@ -2530,6 +2546,7 @@ function CustomerPicker({ search, create, selected, onSelect, onError, online, d
2530
2546
  customers,
2531
2547
  traits: customerTraits,
2532
2548
  onSearch: setQuery,
2549
+ showSearch: false,
2533
2550
  onSelect: (customer) => {
2534
2551
  onSelect(customer);
2535
2552
  setQuery("");
@@ -2675,7 +2692,7 @@ function ChangeDisplay({ change, locale, className, ...viewProps }) {
2675
2692
  }
2676
2693
 
2677
2694
  // src/checkout/cash-tendered.tsx
2678
- import { useEffect as useEffect2, useRef as useRef2, useState as useState7 } from "react";
2695
+ import { useEffect as useEffect2, useRef as useRef2, useState as useState8 } from "react";
2679
2696
  import { Pressable as Pressable18, Text as Text21, TextInput as TextInput8, View as View36 } from "react-native";
2680
2697
  import { formatMoney as formatMoney5, minorUnitDigits as minorUnitDigits2, moneyFromDecimalString } from "@tallyui/core";
2681
2698
  import { cn as cn65 } from "@tallyui/theme";
@@ -2700,13 +2717,13 @@ function CashTendered({
2700
2717
  className,
2701
2718
  ...viewProps
2702
2719
  }) {
2703
- const [internalAmount, setInternalAmount] = useState7(defaultAmount ?? total);
2720
+ const [internalAmount, setInternalAmount] = useState8(defaultAmount ?? total);
2704
2721
  const amount = controlledAmount ?? internalAmount;
2705
2722
  const buttons = quickAmounts ?? defaultQuickAmounts(total);
2706
2723
  const digits = minorUnitDigits2(amount.currency);
2707
2724
  const amountText = String(Math.abs(amount.amount)).padStart(digits + 1, "0");
2708
2725
  const decimal2 = (amount.amount < 0 ? "-" : "") + (digits ? `${amountText.slice(0, -digits)}.${amountText.slice(-digits)}` : amountText);
2709
- const [text, setText] = useState7(decimal2);
2726
+ const [text, setText] = useState8(decimal2);
2710
2727
  const lastTextAmount = useRef2(amount);
2711
2728
  useEffect2(() => {
2712
2729
  if (amount.amount !== lastTextAmount.current.amount || amount.currency !== lastTextAmount.current.currency) {
@@ -2946,7 +2963,7 @@ function OrderDetail({
2946
2963
  }
2947
2964
 
2948
2965
  // src/register/cash-count-input.tsx
2949
- import { useState as useState8 } from "react";
2966
+ import { useState as useState9 } from "react";
2950
2967
  import { Text as Text26, View as View42 } from "react-native";
2951
2968
  import { cn as cn71 } from "@tallyui/theme";
2952
2969
  import { jsx as jsx74, jsxs as jsxs33 } from "react/jsx-runtime";
@@ -2971,7 +2988,7 @@ function CashCountInput({
2971
2988
  className,
2972
2989
  ...viewProps
2973
2990
  }) {
2974
- const [internalCounts, setInternalCounts] = useState8(defaultCounts ?? {});
2991
+ const [internalCounts, setInternalCounts] = useState9(defaultCounts ?? {});
2975
2992
  const counts = controlledCounts ?? internalCounts;
2976
2993
  const total = denominations2.reduce(
2977
2994
  (sum, d) => sum + d.value * (counts[d.value] ?? 0),
@@ -3118,7 +3135,7 @@ function RegisterPicker({ registers, onPick, className }) {
3118
3135
  }
3119
3136
 
3120
3137
  // src/register/open-register-card.tsx
3121
- import { useState as useState9 } from "react";
3138
+ import { useState as useState10 } from "react";
3122
3139
  import { View as View45 } from "react-native";
3123
3140
  import { parseMinor, validAmount } from "@tallyui/pos";
3124
3141
  import { currencySymbol, formatMoney as formatMoney6, minorUnitDigits as minorUnitDigits3 } from "@tallyui/core";
@@ -3129,10 +3146,10 @@ function OpenRegisterCard({ register, currency, configuredFloatMinor, className
3129
3146
  const digits = minorUnitDigits3(currency);
3130
3147
  const lastCountedMinor = register.lastClosure?.counted?.cash ?? null;
3131
3148
  const expectedFloatMinor = configuredFloatMinor ?? lastCountedMinor ?? null;
3132
- const [enteredAmount, setEnteredAmount] = useState9(null);
3149
+ const [enteredAmount, setEnteredAmount] = useState10(null);
3133
3150
  const amount = enteredAmount ?? (expectedFloatMinor != null ? decimal(expectedFloatMinor, digits) : "");
3134
- const [busy, setBusy] = useState9(false);
3135
- const [error, setError] = useState9("");
3151
+ const [busy, setBusy] = useState10(false);
3152
+ const [error, setError] = useState10("");
3136
3153
  const valid = validAmount(amount, digits);
3137
3154
  const countedMinor = valid ? parseMinor(amount, digits) : NaN;
3138
3155
  const open = async () => {
@@ -3267,7 +3284,7 @@ function RegisterBar({
3267
3284
  }
3268
3285
 
3269
3286
  // src/register/movement-sheet.tsx
3270
- import { useRef as useRef3, useState as useState10 } from "react";
3287
+ import { useRef as useRef3, useState as useState11 } from "react";
3271
3288
  import { movementFieldError, normalizeAmount, parseMinor as parseMinor2 } from "@tallyui/pos";
3272
3289
  import { currencySymbol as currencySymbol2, minorUnitDigits as minorUnitDigits4 } from "@tallyui/core";
3273
3290
  import { Fragment as Fragment3, jsx as jsx80, jsxs as jsxs39 } from "react/jsx-runtime";
@@ -3280,11 +3297,11 @@ var AMOUNT_LABEL_ID2 = "movement-amount-label";
3280
3297
  var REASON_LABEL_ID = "movement-reason-label";
3281
3298
  function MovementSheet({ register, type, currency, onDone, onOpenChange, onOpenDrawer }) {
3282
3299
  const digits = minorUnitDigits4(currency);
3283
- const [amount, setAmount] = useState10("");
3284
- const [reason, setReason] = useState10("");
3285
- const [busy, setBusy] = useState10(false);
3300
+ const [amount, setAmount] = useState11("");
3301
+ const [reason, setReason] = useState11("");
3302
+ const [busy, setBusy] = useState11(false);
3286
3303
  const busyRef = useRef3(false);
3287
- const [error, setError] = useState10("");
3304
+ const [error, setError] = useState11("");
3288
3305
  const invalid = movementFieldError({ type, amount, reason });
3289
3306
  const confirm = async () => {
3290
3307
  if (invalid || busyRef.current) return;
@@ -3341,12 +3358,12 @@ function MovementSheet({ register, type, currency, onDone, onOpenChange, onOpenD
3341
3358
  }
3342
3359
 
3343
3360
  // src/register/register-panel.tsx
3344
- import { useState as useState12 } from "react";
3361
+ import { useState as useState13 } from "react";
3345
3362
  import { ScrollView as ScrollView12, useWindowDimensions as useWindowDimensions2, View as View48 } from "react-native";
3346
3363
  import { formatMoney as formatMoney8 } from "@tallyui/core";
3347
3364
 
3348
3365
  // src/register/register-count.tsx
3349
- import { useEffect as useEffect3, useRef as useRef4, useState as useState11 } from "react";
3366
+ import { useEffect as useEffect3, useRef as useRef4, useState as useState12 } from "react";
3350
3367
  import { Platform, Pressable as Pressable22, ScrollView as ScrollView11, useWindowDimensions, View as View47 } from "react-native";
3351
3368
  import {
3352
3369
  closeNeedsApproval,
@@ -3425,18 +3442,18 @@ function RegisterCount({ register, currency, approve, className }) {
3425
3442
  const faces = denominations[currency] ?? denominations.default;
3426
3443
  const { width } = useWindowDimensions();
3427
3444
  const columns = width < 480 ? 3 : 4;
3428
- const [pieces, setPieces] = useState11({});
3429
- const [cashText, setCashText] = useState11(
3445
+ const [pieces, setPieces] = useState12({});
3446
+ const [cashText, setCashText] = useState12(
3430
3447
  () => session?.counted?.cash != null ? minorToDecimal(session.counted.cash, digits) : ""
3431
3448
  );
3432
- const [others, setOthers] = useState11(
3449
+ const [others, setOthers] = useState12(
3433
3450
  () => Object.fromEntries(
3434
3451
  Object.entries(session?.counted ?? {}).filter(([method]) => method !== "cash").map(([method, minor]) => [method, minorToDecimal(minor, digits)])
3435
3452
  )
3436
3453
  );
3437
- const [busy, setBusy] = useState11(false);
3438
- const [error, setError] = useState11("");
3439
- const [refusal, setRefusal] = useState11("");
3454
+ const [busy, setBusy] = useState12(false);
3455
+ const [error, setError] = useState12("");
3456
+ const [refusal, setRefusal] = useState12("");
3440
3457
  const usingTiles = Object.keys(pieces).length > 0;
3441
3458
  const tilesTotal = denominationTotal(pieces);
3442
3459
  const displayAmount = usingTiles ? minorToDecimal(tilesTotal, digits) : cashText;
@@ -3591,9 +3608,9 @@ function RegisterPanel({ register, currency, registerName, open, onOpenChange, c
3591
3608
  const otherTenders = Object.entries(expected).filter(([method, amount]) => method !== "cash" && amount !== 0);
3592
3609
  const { height: windowHeight } = useWindowDimensions2();
3593
3610
  const maxHeight = Math.max(280, windowHeight - DIALOG_VERTICAL_MARGIN);
3594
- const [movementType, setMovementType] = useState12(null);
3595
- const [expanded, setExpanded] = useState12(false);
3596
- const [error, setError] = useState12("");
3611
+ const [movementType, setMovementType] = useState13(null);
3612
+ const [expanded, setExpanded] = useState13(false);
3613
+ const [error, setError] = useState13("");
3597
3614
  const attempt = async (action) => {
3598
3615
  try {
3599
3616
  await action();
@@ -3710,7 +3727,7 @@ function RegisterPanel({ register, currency, registerName, open, onOpenChange, c
3710
3727
  }
3711
3728
 
3712
3729
  // src/register/register-column.tsx
3713
- import { useState as useState13 } from "react";
3730
+ import { useState as useState14 } from "react";
3714
3731
  import { View as View49 } from "react-native";
3715
3732
  import { Fragment as Fragment4, jsx as jsx83, jsxs as jsxs42 } from "react/jsx-runtime";
3716
3733
  function RegisterColumn({
@@ -3724,7 +3741,7 @@ function RegisterColumn({
3724
3741
  cartEmpty,
3725
3742
  children
3726
3743
  }) {
3727
- const [finishing, setFinishing] = useState13(false);
3744
+ const [finishing, setFinishing] = useState14(false);
3728
3745
  if (registerId === null) {
3729
3746
  return /* @__PURE__ */ jsx83(RegisterPicker, { registers, onPick, className: "flex-1" });
3730
3747
  }
@@ -3755,7 +3772,7 @@ function RegisterColumn({
3755
3772
  ] });
3756
3773
  }
3757
3774
  function FinishClose({ register, busy, setBusy }) {
3758
- const [error, setError] = useState13("");
3775
+ const [error, setError] = useState14("");
3759
3776
  const finish = async () => {
3760
3777
  setBusy(true);
3761
3778
  setError("");
@@ -3775,7 +3792,7 @@ function FinishClose({ register, busy, setBusy }) {
3775
3792
  }
3776
3793
 
3777
3794
  // src/register/closure-sheet.tsx
3778
- import { useEffect as useEffect4, useRef as useRef5, useState as useState14 } from "react";
3795
+ import { useEffect as useEffect4, useRef as useRef5, useState as useState15 } from "react";
3779
3796
  import { AccessibilityInfo, Animated, View as View50 } from "react-native";
3780
3797
  import { countVariance as countVariance2, TAX_ROUNDING_MIXED_NOTE, varianceText as varianceText2 } from "@tallyui/pos";
3781
3798
  import { formatMoney as formatMoney9, minorUnitDigits as minorUnitDigits6 } from "@tallyui/core";
@@ -3807,8 +3824,8 @@ function ClosureSheet({ register, currency, onPrint, onDone }) {
3807
3824
  const { lastClosure: closure, blind } = register;
3808
3825
  const digits = minorUnitDigits6(currency);
3809
3826
  const { opacity, scale } = useCompletionMotion();
3810
- const [busy, setBusy] = useState14(false);
3811
- const [error, setError] = useState14("");
3827
+ const [busy, setBusy] = useState15(false);
3828
+ const [error, setError] = useState15("");
3812
3829
  if (!closure) return null;
3813
3830
  const methods = Object.keys(closure.counted);
3814
3831
  const approvedByName = closure.breakdowns.approved_by_name;
@@ -3945,12 +3962,12 @@ function ConnectorStatus({
3945
3962
  }
3946
3963
 
3947
3964
  // src/sale/cart.tsx
3948
- import { useState as useState16 } from "react";
3949
- import { Pressable as Pressable24, Text as Text33, View as View55 } from "react-native";
3965
+ import { useState as useState18 } from "react";
3966
+ import { Pressable as Pressable25, Text as Text34, View as View56 } from "react-native";
3950
3967
  import { buildReceiptData } from "@tallyui/pos";
3951
3968
 
3952
3969
  // src/sale/discount-form.tsx
3953
- import { useState as useState15 } from "react";
3970
+ import { useState as useState16 } from "react";
3954
3971
  import { Pressable as Pressable23, Text as Text32, TextInput as TextInput9, View as View54 } from "react-native";
3955
3972
  import { formatMoney as formatMoney10, minorUnitDigits as minorUnitDigits7, moneyFromDecimalString as moneyFromDecimalString2 } from "@tallyui/core";
3956
3973
  import { jsx as jsx88, jsxs as jsxs47 } from "react/jsx-runtime";
@@ -3970,9 +3987,9 @@ function parseDiscount(type, text, currency) {
3970
3987
  var discountLabel = (discount, currency) => discount.type === "percentage" ? `${discount.value}%` : formatMoney10({ amount: discount.amountMinor, currency }) ?? String(discount.amountMinor);
3971
3988
  var button = "rounded-md border border-border px-3 py-2 min-h-11 items-center justify-center";
3972
3989
  function DiscountForm({ title, currency, onApply, onClose }) {
3973
- const [type, setType] = useState15("percentage");
3974
- const [text, setText] = useState15("");
3975
- const [error, setError] = useState15(null);
3990
+ const [type, setType] = useState16("percentage");
3991
+ const [text, setText] = useState16("");
3992
+ const [error, setError] = useState16(null);
3976
3993
  function apply() {
3977
3994
  const parsed = parseDiscount(type, text, currency);
3978
3995
  const refused = typeof parsed === "string" ? parsed : onApply(parsed);
@@ -4040,17 +4057,79 @@ function DiscountChips({ discounts, currency, onRemove, prefix, amounts = [] })
4040
4057
  }) });
4041
4058
  }
4042
4059
 
4060
+ // src/sale/price-form.tsx
4061
+ import { useState as useState17 } from "react";
4062
+ import { Pressable as Pressable24, Text as Text33, TextInput as TextInput10, View as View55 } from "react-native";
4063
+ import { formatMoney as formatMoney11, minorUnitDigits as minorUnitDigits8, moneyFromDecimalString as moneyFromDecimalString3 } from "@tallyui/core";
4064
+ import { jsx as jsx89, jsxs as jsxs48 } from "react/jsx-runtime";
4065
+ function parsePrice(text, currency) {
4066
+ const raw = text.trim();
4067
+ const trimmed = raw.split(",").length === 2 ? raw.replace(",", ".") : raw;
4068
+ if (!trimmed) return "Enter a price.";
4069
+ if (!/^-?\d+(\.\d+)?$/.test(trimmed)) return "Enter a number.";
4070
+ if (Number(trimmed) < 0) return "Enter a price of 0 or more.";
4071
+ const digits = Math.min(2, minorUnitDigits8(currency));
4072
+ if ((trimmed.split(".")[1]?.length ?? 0) > digits) return digits ? `Use at most ${digits} decimal places.` : "Use a whole amount.";
4073
+ return moneyFromDecimalString3(trimmed, currency)?.amount ?? "Enter a number.";
4074
+ }
4075
+ var button2 = "rounded-md border border-border px-3 py-2 min-h-11 items-center justify-center";
4076
+ function PriceForm({ lineName, currency, currentMinor, onApply, onClose }) {
4077
+ const [text, setText] = useState17("");
4078
+ const [reason, setReason] = useState17("");
4079
+ const [error, setError] = useState17(null);
4080
+ const title = `Price for ${lineName}`;
4081
+ function apply() {
4082
+ const parsed = parsePrice(text, currency);
4083
+ const refused = typeof parsed === "string" ? parsed : onApply(parsed, reason.trim() || void 0);
4084
+ setError(refused);
4085
+ if (refused === null) onClose();
4086
+ }
4087
+ return /* @__PURE__ */ jsxs48(View55, { testID: "price-form", role: "group", accessibilityLabel: title, className: "gap-2 px-3 py-2", children: [
4088
+ /* @__PURE__ */ jsx89(Text33, { className: "font-semibold text-foreground", children: title }),
4089
+ /* @__PURE__ */ jsx89(Text33, { className: "text-muted-foreground", children: formatMoney11({ amount: currentMinor, currency }) }),
4090
+ /* @__PURE__ */ jsx89(
4091
+ TextInput10,
4092
+ {
4093
+ testID: "price-input",
4094
+ accessibilityLabel: "Price value",
4095
+ value: text,
4096
+ onChangeText: setText,
4097
+ onSubmitEditing: apply,
4098
+ inputMode: "decimal",
4099
+ placeholder: currency,
4100
+ className: "min-w-0 rounded-md border border-border bg-background px-3 py-2 text-foreground"
4101
+ }
4102
+ ),
4103
+ /* @__PURE__ */ jsx89(
4104
+ TextInput10,
4105
+ {
4106
+ testID: "price-reason",
4107
+ accessibilityLabel: "Reason (optional)",
4108
+ placeholder: "Reason (optional)",
4109
+ value: reason,
4110
+ onChangeText: setReason,
4111
+ className: "min-w-0 rounded-md border border-border bg-background px-3 py-2 text-foreground"
4112
+ }
4113
+ ),
4114
+ error ? /* @__PURE__ */ jsx89(Text33, { testID: "price-error", accessibilityRole: "alert", className: "text-destructive", children: error }) : null,
4115
+ /* @__PURE__ */ jsxs48(View55, { className: "flex-row gap-2", children: [
4116
+ /* @__PURE__ */ jsx89(Pressable24, { testID: "price-apply", accessibilityRole: "button", onPress: apply, className: `${button2} bg-primary`, children: /* @__PURE__ */ jsx89(Text33, { className: "font-semibold text-primary-foreground", children: "Apply" }) }),
4117
+ /* @__PURE__ */ jsx89(Pressable24, { testID: "price-cancel", accessibilityRole: "button", onPress: onClose, className: `${button2} bg-card`, children: /* @__PURE__ */ jsx89(Text33, { className: "text-foreground", children: "Cancel" }) })
4118
+ ] })
4119
+ ] });
4120
+ }
4121
+
4043
4122
  // src/sale/cart.tsx
4044
- import { Fragment as Fragment5, jsx as jsx89, jsxs as jsxs48 } from "react/jsx-runtime";
4045
- function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
4123
+ import { Fragment as Fragment5, jsx as jsx90, jsxs as jsxs49 } from "react/jsx-runtime";
4124
+ function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%`, canEditPrice = false, onPriceChange }) {
4046
4125
  const { order } = sale;
4047
4126
  const money = (amount) => ({ amount, currency: order.currency });
4048
4127
  const { totals } = buildReceiptData(order, { storeName: "" });
4049
4128
  const taxRows = totals.taxLines.map((line) => ({ label: taxLabel(line.ratePpm), amount: money(line.amountMinor) }));
4050
4129
  const display = (lineId) => order.display.lines.find((line) => line.lineId === lineId);
4051
4130
  const orderAmounts = order.discounts.length === 1 ? [{ discountId: order.discounts[0].id, amountMinor: order.display.orderDiscountMinor }] : [];
4052
- const [form, setForm] = useState16(null);
4053
- const discountForm = (lineId, title) => form?.lineId === lineId ? /* @__PURE__ */ jsx89(
4131
+ const [form, setForm] = useState18(null);
4132
+ const discountForm = (lineId, title) => form?.type === "discount" && form.lineId === lineId ? /* @__PURE__ */ jsx90(
4054
4133
  DiscountForm,
4055
4134
  {
4056
4135
  title,
@@ -4061,8 +4140,11 @@ function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
4061
4140
  lineId ?? "order"
4062
4141
  ) : null;
4063
4142
  const pay = `min-h-12 flex-1 justify-center rounded-md bg-primary px-4 py-3 ${!order.lineItems.length ? "opacity-50" : ""}`;
4064
- const renderItem = (line) => /* @__PURE__ */ jsxs48(Fragment5, { children: [
4065
- /* @__PURE__ */ jsx89(CartLineActions, { actions: [{ id: "discount", label: "Discount", color: "text-primary", onPress: () => setForm({ lineId: line.id }) }], children: /* @__PURE__ */ jsx89(
4143
+ const renderItem = (line) => /* @__PURE__ */ jsxs49(Fragment5, { children: [
4144
+ /* @__PURE__ */ jsx90(CartLineActions, { actions: [
4145
+ { id: "discount", label: "Discount", color: "text-primary", onPress: () => setForm({ type: "discount", lineId: line.id }) },
4146
+ ...canEditPrice ? [{ id: "price", label: "Price", color: "text-primary", onPress: () => setForm({ type: "price", lineId: line.id }) }] : []
4147
+ ], children: /* @__PURE__ */ jsx90(
4066
4148
  CartLine,
4067
4149
  {
4068
4150
  name: line.name,
@@ -4071,50 +4153,66 @@ function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
4071
4153
  lineTotal: money(display(line.id).amountMinor)
4072
4154
  }
4073
4155
  ) }),
4074
- /* @__PURE__ */ jsx89(DiscountChips, { discounts: line.discounts, amounts: display(line.id).discounts, currency: order.currency, onRemove: sale.removeDiscount }),
4075
- /* @__PURE__ */ jsxs48(View55, { className: "flex-row gap-4 px-3 py-2", children: [
4076
- /* @__PURE__ */ jsx89(
4077
- Pressable24,
4156
+ /* @__PURE__ */ jsx90(DiscountChips, { discounts: line.discounts, amounts: display(line.id).discounts, currency: order.currency, onRemove: sale.removeDiscount }),
4157
+ /* @__PURE__ */ jsxs49(View56, { className: "flex-row gap-4 px-3 py-2", children: [
4158
+ /* @__PURE__ */ jsx90(
4159
+ Pressable25,
4078
4160
  {
4079
4161
  accessibilityRole: "button",
4080
4162
  accessibilityLabel: `Decrease ${line.name}`,
4081
4163
  onPress: () => sale.setQuantity(line.id, line.quantity - 1),
4082
4164
  className: "rounded-md border border-border bg-card px-3 py-2 min-h-11 min-w-11 items-center justify-center",
4083
- children: /* @__PURE__ */ jsx89(Text33, { className: "text-center text-foreground", children: "\u2212" })
4165
+ children: /* @__PURE__ */ jsx90(Text34, { className: "text-center text-foreground", children: "\u2212" })
4084
4166
  }
4085
4167
  ),
4086
- /* @__PURE__ */ jsx89(
4087
- Pressable24,
4168
+ /* @__PURE__ */ jsx90(
4169
+ Pressable25,
4088
4170
  {
4089
4171
  accessibilityRole: "button",
4090
4172
  accessibilityLabel: `Increase ${line.name}`,
4091
4173
  onPress: () => sale.setQuantity(line.id, line.quantity + 1),
4092
4174
  className: "rounded-md border border-border bg-card px-3 py-2 min-h-11 min-w-11 items-center justify-center",
4093
- children: /* @__PURE__ */ jsx89(Text33, { className: "text-center text-foreground", children: "+" })
4175
+ children: /* @__PURE__ */ jsx90(Text34, { className: "text-center text-foreground", children: "+" })
4094
4176
  }
4095
4177
  ),
4096
- /* @__PURE__ */ jsx89(
4097
- Pressable24,
4178
+ /* @__PURE__ */ jsx90(
4179
+ Pressable25,
4098
4180
  {
4099
4181
  accessibilityRole: "button",
4100
4182
  accessibilityLabel: `Remove ${line.name}`,
4101
4183
  onPress: () => sale.remove(line.id),
4102
4184
  className: "rounded-md border border-border bg-card px-3 py-2 min-h-11 min-w-11 items-center justify-center",
4103
- children: /* @__PURE__ */ jsx89(Text33, { className: "text-center text-foreground", children: "Remove" })
4185
+ children: /* @__PURE__ */ jsx90(Text34, { className: "text-center text-foreground", children: "Remove" })
4104
4186
  }
4105
4187
  )
4106
4188
  ] }),
4107
- discountForm(line.id, `Discount on ${line.name}`)
4189
+ discountForm(line.id, `Discount on ${line.name}`),
4190
+ canEditPrice && form?.type === "price" && form.lineId === line.id ? /* @__PURE__ */ jsx90(
4191
+ PriceForm,
4192
+ {
4193
+ lineName: line.name,
4194
+ currency: order.currency,
4195
+ currentMinor: line.unitPriceMinor,
4196
+ onClose: () => setForm(null),
4197
+ onApply: (amount, reason) => {
4198
+ const fromMinor = line.unitPriceMinor;
4199
+ const refused = sale.setUnitPrice(line.id, amount);
4200
+ if (refused === null) onPriceChange?.({ lineId: line.id, fromMinor, toMinor: amount, reason });
4201
+ return refused;
4202
+ }
4203
+ },
4204
+ line.id
4205
+ ) : null
4108
4206
  ] });
4109
- return /* @__PURE__ */ jsx89(
4207
+ return /* @__PURE__ */ jsx90(
4110
4208
  CartPanel,
4111
4209
  {
4112
4210
  dataSet: { print: "hide" },
4113
4211
  items: order.lineItems,
4114
4212
  renderItem,
4115
- emptyState: /* @__PURE__ */ jsx89(Text33, { testID: "cart-empty", className: "px-3 py-2 text-muted-foreground", children: "Scan or tap a product to start a sale." }),
4116
- afterItems: order.lineItems.length ? /* @__PURE__ */ jsxs48(View55, { className: "gap-3 px-3 py-2", children: [
4117
- /* @__PURE__ */ jsx89(
4213
+ emptyState: /* @__PURE__ */ jsx90(Text34, { testID: "cart-empty", className: "px-3 py-2 text-muted-foreground", children: "Scan or tap a product to start a sale." }),
4214
+ afterItems: order.lineItems.length ? /* @__PURE__ */ jsxs49(View56, { className: "gap-3 px-3 py-2", children: [
4215
+ /* @__PURE__ */ jsx90(
4118
4216
  DiscountChips,
4119
4217
  {
4120
4218
  discounts: order.discounts,
@@ -4124,18 +4222,18 @@ function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
4124
4222
  prefix: "Order discount"
4125
4223
  }
4126
4224
  ),
4127
- form?.lineId === null ? discountForm(null, "Order discount") : /* @__PURE__ */ jsx89(
4128
- Pressable24,
4225
+ form?.lineId === null ? discountForm(null, "Order discount") : /* @__PURE__ */ jsx90(
4226
+ Pressable25,
4129
4227
  {
4130
4228
  accessibilityRole: "button",
4131
- onPress: () => setForm({ lineId: null }),
4229
+ onPress: () => setForm({ type: "discount", lineId: null }),
4132
4230
  className: "self-start rounded-md border border-border bg-card px-4 py-2 min-h-11 justify-center",
4133
- children: /* @__PURE__ */ jsx89(Text33, { className: "text-foreground", children: "Order discount" })
4231
+ children: /* @__PURE__ */ jsx90(Text34, { className: "text-foreground", children: "Order discount" })
4134
4232
  }
4135
4233
  )
4136
4234
  ] }) : void 0,
4137
- footer: /* @__PURE__ */ jsxs48(View55, { testID: "cart-footer", className: "gap-3 pb-4", children: [
4138
- /* @__PURE__ */ jsx89(
4235
+ footer: /* @__PURE__ */ jsxs49(View56, { testID: "cart-footer", className: "gap-3 pb-4", children: [
4236
+ /* @__PURE__ */ jsx90(
4139
4237
  CartTotal,
4140
4238
  {
4141
4239
  subtotal: money(totals.subtotalMinor),
@@ -4145,10 +4243,10 @@ function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
4145
4243
  taxInclusive: totals.taxInclusive
4146
4244
  }
4147
4245
  ),
4148
- sale.error ? /* @__PURE__ */ jsx89(Text33, { accessibilityRole: "alert", className: "text-destructive", children: sale.error }) : null,
4149
- /* @__PURE__ */ jsxs48(View55, { className: "flex-row gap-3", children: [
4150
- /* @__PURE__ */ jsx89(Pressable24, { accessibilityRole: "button", disabled: !order.lineItems.length, onPress: () => sale.startTender("cash"), className: pay, children: /* @__PURE__ */ jsx89(Text33, { className: "text-center font-semibold text-primary-foreground", children: "Cash" }) }),
4151
- /* @__PURE__ */ jsx89(Pressable24, { accessibilityRole: "button", disabled: !order.lineItems.length, onPress: () => sale.startTender("external"), className: pay, children: /* @__PURE__ */ jsx89(Text33, { className: "text-center font-semibold text-primary-foreground", children: "Card terminal" }) })
4246
+ sale.error ? /* @__PURE__ */ jsx90(Text34, { accessibilityRole: "alert", className: "text-destructive", children: sale.error }) : null,
4247
+ /* @__PURE__ */ jsxs49(View56, { className: "flex-row gap-3", children: [
4248
+ /* @__PURE__ */ jsx90(Pressable25, { accessibilityRole: "button", disabled: !order.lineItems.length, onPress: () => sale.startTender("cash"), className: pay, children: /* @__PURE__ */ jsx90(Text34, { className: "text-center font-semibold text-primary-foreground", children: "Cash" }) }),
4249
+ /* @__PURE__ */ jsx90(Pressable25, { accessibilityRole: "button", disabled: !order.lineItems.length, onPress: () => sale.startTender("external"), className: pay, children: /* @__PURE__ */ jsx90(Text34, { className: "text-center font-semibold text-primary-foreground", children: "Card terminal" }) })
4152
4250
  ] })
4153
4251
  ] })
4154
4252
  }
@@ -4156,17 +4254,17 @@ function Cart({ sale, taxLabel = (ratePpm) => `Tax ${ratePpm / 1e4}%` }) {
4156
4254
  }
4157
4255
 
4158
4256
  // src/sale/cart-bar.tsx
4159
- import { Pressable as Pressable25, Text as Text34 } from "react-native";
4160
- import { formatMoney as formatMoney11 } from "@tallyui/core";
4257
+ import { Pressable as Pressable26, Text as Text35 } from "react-native";
4258
+ import { formatMoney as formatMoney12 } from "@tallyui/core";
4161
4259
  import { buildReceiptData as buildReceiptData2 } from "@tallyui/pos";
4162
- import { jsx as jsx90, jsxs as jsxs49 } from "react/jsx-runtime";
4260
+ import { jsx as jsx91, jsxs as jsxs50 } from "react/jsx-runtime";
4163
4261
  function CartBar({ sale, onOpen }) {
4164
4262
  const { order } = sale;
4165
4263
  const count2 = order.lineItems.reduce((sum, line) => sum + line.quantity, 0);
4166
- const total = formatMoney11({ amount: buildReceiptData2(order, { storeName: "" }).totals.totalMinor, currency: order.currency });
4264
+ const total = formatMoney12({ amount: buildReceiptData2(order, { storeName: "" }).totals.totalMinor, currency: order.currency });
4167
4265
  const items = `${count2} ${count2 === 1 ? "item" : "items"}`;
4168
- return /* @__PURE__ */ jsxs49(
4169
- Pressable25,
4266
+ return /* @__PURE__ */ jsxs50(
4267
+ Pressable26,
4170
4268
  {
4171
4269
  accessibilityRole: "button",
4172
4270
  accessibilityLabel: count2 ? `Open cart, ${items}, ${total}` : "Cart is empty",
@@ -4174,8 +4272,8 @@ function CartBar({ sale, onOpen }) {
4174
4272
  onPress: onOpen,
4175
4273
  className: `min-h-14 mx-3 mb-3 flex-row items-center justify-between rounded-md bg-primary px-4 py-3 ${count2 ? "" : "opacity-50"}`,
4176
4274
  children: [
4177
- /* @__PURE__ */ jsx90(Text34, { className: "font-bold text-primary-foreground", children: count2 ? `Cart \xB7 ${items}` : "Cart is empty" }),
4178
- count2 ? /* @__PURE__ */ jsxs49(Text34, { className: "font-bold text-primary-foreground", children: [
4275
+ /* @__PURE__ */ jsx91(Text35, { className: "font-bold text-primary-foreground", children: count2 ? `Cart \xB7 ${items}` : "Cart is empty" }),
4276
+ count2 ? /* @__PURE__ */ jsxs50(Text35, { className: "font-bold text-primary-foreground", children: [
4179
4277
  total,
4180
4278
  " \u203A"
4181
4279
  ] }) : null
@@ -4185,17 +4283,17 @@ function CartBar({ sale, onOpen }) {
4185
4283
  }
4186
4284
 
4187
4285
  // src/sale/tender.tsx
4188
- import { Pressable as Pressable26, Text as Text35, TextInput as TextInput10, View as View56 } from "react-native";
4189
- import { formatMoney as formatMoney12 } from "@tallyui/core";
4190
- import { Fragment as Fragment6, jsx as jsx91, jsxs as jsxs50 } from "react/jsx-runtime";
4286
+ import { Pressable as Pressable27, Text as Text36, TextInput as TextInput11, View as View57 } from "react-native";
4287
+ import { formatMoney as formatMoney13 } from "@tallyui/core";
4288
+ import { Fragment as Fragment6, jsx as jsx92, jsxs as jsxs51 } from "react/jsx-runtime";
4191
4289
  var REFERENCE_MAX = 255;
4192
4290
  function Tender({ sale }) {
4193
4291
  const { order, stage } = sale;
4194
4292
  if (stage.kind !== "tender") return null;
4195
4293
  const money = (amount) => ({ amount, currency: order.currency });
4196
- return /* @__PURE__ */ jsxs50(View56, { dataSet: { print: "hide" }, className: "gap-4 p-4", children: [
4197
- stage.method === "cash" ? /* @__PURE__ */ jsxs50(Fragment6, { children: [
4198
- /* @__PURE__ */ jsx91(
4294
+ return /* @__PURE__ */ jsxs51(View57, { dataSet: { print: "hide" }, className: "gap-4 p-4", children: [
4295
+ stage.method === "cash" ? /* @__PURE__ */ jsxs51(Fragment6, { children: [
4296
+ /* @__PURE__ */ jsx92(
4199
4297
  CashTendered,
4200
4298
  {
4201
4299
  total: money(order.totalMinor),
@@ -4203,19 +4301,19 @@ function Tender({ sale }) {
4203
4301
  onChangeAmount: (amount) => sale.setTender({ method: "cash", amountMinor: amount.amount })
4204
4302
  }
4205
4303
  ),
4206
- /* @__PURE__ */ jsx91(ChangeDisplay, { change: money(order.changeDueMinor) }),
4207
- order.balanceDueMinor > 0 ? /* @__PURE__ */ jsxs50(Text35, { className: "text-foreground", children: [
4304
+ /* @__PURE__ */ jsx92(ChangeDisplay, { change: money(order.changeDueMinor) }),
4305
+ order.balanceDueMinor > 0 ? /* @__PURE__ */ jsxs51(Text36, { className: "text-foreground", children: [
4208
4306
  "Balance due: ",
4209
- formatMoney12(money(order.balanceDueMinor))
4307
+ formatMoney13(money(order.balanceDueMinor))
4210
4308
  ] }) : null,
4211
- /* @__PURE__ */ jsx91(Pressable26, { accessibilityRole: "button", disabled: order.balanceDueMinor > 0, onPress: sale.complete, className: `rounded-md bg-primary px-4 py-3 ${order.balanceDueMinor > 0 ? "opacity-50" : ""}`, children: /* @__PURE__ */ jsx91(Text35, { className: "text-center font-semibold text-primary-foreground", children: "Complete sale" }) })
4212
- ] }) : /* @__PURE__ */ jsxs50(Fragment6, { children: [
4213
- /* @__PURE__ */ jsxs50(Text35, { className: "text-foreground", children: [
4309
+ /* @__PURE__ */ jsx92(Pressable27, { accessibilityRole: "button", disabled: order.balanceDueMinor > 0, onPress: sale.complete, className: `rounded-md bg-primary px-4 py-3 ${order.balanceDueMinor > 0 ? "opacity-50" : ""}`, children: /* @__PURE__ */ jsx92(Text36, { className: "text-center font-semibold text-primary-foreground", children: "Complete sale" }) })
4310
+ ] }) : /* @__PURE__ */ jsxs51(Fragment6, { children: [
4311
+ /* @__PURE__ */ jsxs51(Text36, { className: "text-foreground", children: [
4214
4312
  "Card terminal: ",
4215
- formatMoney12(money(order.totalMinor))
4313
+ formatMoney13(money(order.totalMinor))
4216
4314
  ] }),
4217
- /* @__PURE__ */ jsx91(
4218
- TextInput10,
4315
+ /* @__PURE__ */ jsx92(
4316
+ TextInput11,
4219
4317
  {
4220
4318
  accessibilityLabel: "Terminal reference",
4221
4319
  placeholder: "Terminal reference",
@@ -4225,23 +4323,23 @@ function Tender({ sale }) {
4225
4323
  className: "rounded-md border border-border px-3 py-2 text-foreground"
4226
4324
  }
4227
4325
  ),
4228
- /* @__PURE__ */ jsx91(Pressable26, { accessibilityRole: "button", onPress: sale.complete, className: "rounded-md bg-primary px-4 py-3", children: /* @__PURE__ */ jsx91(Text35, { className: "text-center font-semibold text-primary-foreground", children: "Payment approved on terminal" }) })
4326
+ /* @__PURE__ */ jsx92(Pressable27, { accessibilityRole: "button", onPress: sale.complete, className: "rounded-md bg-primary px-4 py-3", children: /* @__PURE__ */ jsx92(Text36, { className: "text-center font-semibold text-primary-foreground", children: "Payment approved on terminal" }) })
4229
4327
  ] }),
4230
- sale.error ? /* @__PURE__ */ jsx91(Text35, { accessibilityRole: "alert", className: "text-destructive", children: sale.error }) : null,
4231
- sale.canContinue ? /* @__PURE__ */ jsxs50(Fragment6, { children: [
4232
- /* @__PURE__ */ jsx91(Text35, { className: "text-foreground", children: "This sale is stored and will be sent. Continue to the next sale." }),
4233
- /* @__PURE__ */ jsx91(Pressable26, { accessibilityRole: "button", onPress: () => sale.continueSale(), className: "rounded-md bg-primary px-4 py-3", children: /* @__PURE__ */ jsx91(Text35, { className: "text-center font-semibold text-primary-foreground", children: "Continue" }) })
4328
+ sale.error ? /* @__PURE__ */ jsx92(Text36, { accessibilityRole: "alert", className: "text-destructive", children: sale.error }) : null,
4329
+ sale.canContinue ? /* @__PURE__ */ jsxs51(Fragment6, { children: [
4330
+ /* @__PURE__ */ jsx92(Text36, { className: "text-foreground", children: "This sale is stored and will be sent. Continue to the next sale." }),
4331
+ /* @__PURE__ */ jsx92(Pressable27, { accessibilityRole: "button", onPress: () => sale.continueSale(), className: "rounded-md bg-primary px-4 py-3", children: /* @__PURE__ */ jsx92(Text36, { className: "text-center font-semibold text-primary-foreground", children: "Continue" }) })
4234
4332
  ] }) : null,
4235
- /* @__PURE__ */ jsx91(Pressable26, { accessibilityRole: "button", onPress: sale.cancelTender, className: "rounded-md border border-border bg-card px-4 py-3", children: /* @__PURE__ */ jsx91(Text35, { className: "text-center text-foreground", children: "Back" }) })
4333
+ /* @__PURE__ */ jsx92(Pressable27, { accessibilityRole: "button", onPress: sale.cancelTender, className: "rounded-md border border-border bg-card px-4 py-3", children: /* @__PURE__ */ jsx92(Text36, { className: "text-center text-foreground", children: "Back" }) })
4236
4334
  ] });
4237
4335
  }
4238
4336
 
4239
4337
  // src/sale/catalogue.tsx
4240
- import { useEffect as useEffect5, useMemo as useMemo2, useState as useState17 } from "react";
4241
- import { Pressable as Pressable27, Text as Text36, View as View57 } from "react-native";
4338
+ import { useEffect as useEffect5, useMemo as useMemo2, useState as useState19 } from "react";
4339
+ import { Pressable as Pressable28, Text as Text37, View as View58 } from "react-native";
4242
4340
  import { useStockOverlaid, useStockOverlayAsOf } from "@tallyui/core";
4243
4341
  import { catalogueEntries, findEntryByCode, searchProducts, variantPriceLabel } from "@tallyui/pos";
4244
- import { jsx as jsx92, jsxs as jsxs51 } from "react/jsx-runtime";
4342
+ import { jsx as jsx93, jsxs as jsxs52 } from "react/jsx-runtime";
4245
4343
  var MIN_TILE_WIDTH = 160;
4246
4344
  var STOCK_LABEL = {
4247
4345
  in_stock: "In Stock",
@@ -4267,9 +4365,9 @@ function Catalogue({ products, traits, currency, onSelect, statusText, statusAcc
4267
4365
  const parsedOverlayAsOf = overlayAsOf ? new Date(overlayAsOf) : void 0;
4268
4366
  const validOverlayAsOf = parsedOverlayAsOf && !isNaN(parsedOverlayAsOf.getTime()) ? parsedOverlayAsOf : void 0;
4269
4367
  const stockAsOf = laterOf(laterOf(lastStockCheckAt, validOverlayAsOf), lastSyncedAt);
4270
- const [query, setQuery] = useState17("");
4271
- const [chooserId, setChooserId] = useState17(null);
4272
- const [width, setWidth] = useState17(0);
4368
+ const [query, setQuery] = useState19("");
4369
+ const [chooserId, setChooserId] = useState19(null);
4370
+ const [width, setWidth] = useState19(0);
4273
4371
  const columns = Math.max(2, Math.min(6, Math.floor((width - 8) / (MIN_TILE_WIDTH + 8))));
4274
4372
  const entries = useMemo2(() => catalogueEntries(shown, traits, { currency }), [shown, traits, currency]);
4275
4373
  const results = useMemo2(() => searchProducts(shown, query, traits), [shown, query, traits]);
@@ -4281,9 +4379,9 @@ function Catalogue({ products, traits, currency, onSelect, statusText, statusAcc
4281
4379
  onSelect(entry);
4282
4380
  setChooserId(null);
4283
4381
  }
4284
- return /* @__PURE__ */ jsxs51(View57, { className: "flex-1", onLayout: (event) => setWidth(event.nativeEvent.layout.width), children: [
4285
- /* @__PURE__ */ jsxs51(View57, { className: "gap-2 border-b border-border bg-card px-4 pb-3 pt-3", children: [
4286
- /* @__PURE__ */ jsx92(
4382
+ return /* @__PURE__ */ jsxs52(View58, { className: "flex-1", onLayout: (event) => setWidth(event.nativeEvent.layout.width), children: [
4383
+ /* @__PURE__ */ jsxs52(View58, { className: "gap-2 border-b border-border bg-card px-4 pb-3 pt-3", children: [
4384
+ /* @__PURE__ */ jsx93(
4287
4385
  SearchInput,
4288
4386
  {
4289
4387
  value: query,
@@ -4300,25 +4398,25 @@ function Catalogue({ products, traits, currency, onSelect, statusText, statusAcc
4300
4398
  }
4301
4399
  }
4302
4400
  ),
4303
- statusText || statusAccessory ? /* @__PURE__ */ jsxs51(View57, { testID: "catalogue-status-row", className: "flex-row items-center gap-2", children: [
4304
- statusText ? /* @__PURE__ */ jsxs51(Text36, { className: "flex-1 text-xs text-muted-foreground", numberOfLines: statusAccessory ? 1 : void 0, children: [
4401
+ statusText || statusAccessory ? /* @__PURE__ */ jsxs52(View58, { testID: "catalogue-status-row", className: "flex-row items-center gap-2", children: [
4402
+ statusText ? /* @__PURE__ */ jsxs52(Text37, { className: "flex-1 text-xs text-muted-foreground", numberOfLines: statusAccessory ? 1 : void 0, children: [
4305
4403
  statusText,
4306
4404
  query.trim() ? ` \xB7 ${results.length.toLocaleString()} matching` : ""
4307
4405
  ] }) : null,
4308
4406
  statusAccessory
4309
4407
  ] }) : null,
4310
- choices.length > 0 ? /* @__PURE__ */ jsxs51(View57, { accessibilityLabel: "Choose variant", className: "gap-2", children: [
4311
- choices.map((entry) => /* @__PURE__ */ jsxs51(
4312
- Pressable27,
4408
+ choices.length > 0 ? /* @__PURE__ */ jsxs52(View58, { accessibilityLabel: "Choose variant", className: "gap-2", children: [
4409
+ choices.map((entry) => /* @__PURE__ */ jsxs52(
4410
+ Pressable28,
4313
4411
  {
4314
4412
  accessibilityRole: "button",
4315
4413
  onPress: () => select(entry),
4316
4414
  className: "gap-1 rounded-md border border-border p-3",
4317
4415
  children: [
4318
- /* @__PURE__ */ jsx92(Text36, { className: "font-semibold text-foreground", children: entry.variant.title }),
4319
- /* @__PURE__ */ jsx92(Text36, { className: "text-muted-foreground", children: entry.variant.sku }),
4320
- /* @__PURE__ */ jsx92(Text36, { className: "text-foreground", children: variantPriceLabel(entry.variant, currency) }),
4321
- /* @__PURE__ */ jsxs51(Text36, { className: "text-muted-foreground", children: [
4416
+ /* @__PURE__ */ jsx93(Text37, { className: "font-semibold text-foreground", children: entry.variant.title }),
4417
+ /* @__PURE__ */ jsx93(Text37, { className: "text-muted-foreground", children: entry.variant.sku }),
4418
+ /* @__PURE__ */ jsx93(Text37, { className: "text-foreground", children: variantPriceLabel(entry.variant, currency) }),
4419
+ /* @__PURE__ */ jsxs52(Text37, { className: "text-muted-foreground", children: [
4322
4420
  STOCK_LABEL[entry.variant.stock.status],
4323
4421
  " \xB7 ",
4324
4422
  stockAsOf ? `as of ${formatStockSyncTime(stockAsOf, void 0, hour12)}` : "not yet synced"
@@ -4327,10 +4425,10 @@ function Catalogue({ products, traits, currency, onSelect, statusText, statusAcc
4327
4425
  },
4328
4426
  entry.variant.id
4329
4427
  )),
4330
- /* @__PURE__ */ jsx92(Pressable27, { accessibilityRole: "button", onPress: () => setChooserId(null), className: "rounded-md border border-border bg-card px-4 py-3", children: /* @__PURE__ */ jsx92(Text36, { className: "text-center text-foreground", children: "Cancel" }) })
4428
+ /* @__PURE__ */ jsx93(Pressable28, { accessibilityRole: "button", onPress: () => setChooserId(null), className: "rounded-md border border-border bg-card px-4 py-3", children: /* @__PURE__ */ jsx93(Text37, { className: "text-center text-foreground", children: "Cancel" }) })
4331
4429
  ] }) : null
4332
4430
  ] }),
4333
- /* @__PURE__ */ jsx92(
4431
+ /* @__PURE__ */ jsx93(
4334
4432
  ProductGrid,
4335
4433
  {
4336
4434
  items: results,
@@ -4339,18 +4437,18 @@ function Catalogue({ products, traits, currency, onSelect, statusText, statusAcc
4339
4437
  // TallyUI's ProductCard has no children slot, so the tile is composed directly here
4340
4438
  // (same structure/classes as ProductCard) to add the stock badge as a fourth child,
4341
4439
  // inside the card and centred with the rest, rather than adding a slot to ProductCard (out of scope for TV6b).
4342
- /* @__PURE__ */ jsx92(Pressable27, { accessibilityRole: "button", testID: `product-tile-${traits.getName(product)}`, onPress: () => {
4440
+ /* @__PURE__ */ jsx93(Pressable28, { accessibilityRole: "button", testID: `product-tile-${traits.getName(product)}`, onPress: () => {
4343
4441
  const variants = entries.filter((entry) => entry.product === product);
4344
4442
  if (variants.length === 1) select(variants[0]);
4345
4443
  else setChooserId(traits.getId(product));
4346
- }, children: /* @__PURE__ */ jsxs51(VStack, { space: "sm", className: "items-center rounded-lg border border-border bg-card p-3", children: [
4347
- /* @__PURE__ */ jsx92(ProductImage, { doc: product, size: 80, className: "rounded-md" }),
4348
- /* @__PURE__ */ jsx92(ProductTitle, { doc: product, className: "text-sm", numberOfLines: 2 }),
4349
- /* @__PURE__ */ jsx92(ProductPrice, { doc: product }),
4350
- /* @__PURE__ */ jsx92(ProductStockBadge, { doc: product, showAsOf: false, className: "self-center" })
4444
+ }, children: /* @__PURE__ */ jsxs52(VStack, { space: "sm", className: "items-center rounded-lg border border-border bg-card p-3", children: [
4445
+ /* @__PURE__ */ jsx93(ProductImage, { doc: product, size: 80, className: "rounded-md" }),
4446
+ /* @__PURE__ */ jsx93(ProductTitle, { doc: product, className: "text-sm", numberOfLines: 2 }),
4447
+ /* @__PURE__ */ jsx93(ProductPrice, { doc: product }),
4448
+ /* @__PURE__ */ jsx93(ProductStockBadge, { doc: product, showAsOf: false, className: "self-center" })
4351
4449
  ] }) })
4352
4450
  ),
4353
- emptyState: /* @__PURE__ */ jsx92(Text36, { className: "mt-10 text-center text-sm text-muted-foreground", children: query.trim() ? `No products match "${query.trim()}".` : isLoading ? "Loading products\u2026" : "No products yet." })
4451
+ emptyState: /* @__PURE__ */ jsx93(Text37, { className: "mt-10 text-center text-sm text-muted-foreground", children: query.trim() ? `No products match "${query.trim()}".` : isLoading ? "Loading products\u2026" : "No products yet." })
4354
4452
  }
4355
4453
  )
4356
4454
  ] });
@@ -4358,8 +4456,8 @@ function Catalogue({ products, traits, currency, onSelect, statusText, statusAcc
4358
4456
 
4359
4457
  // src/sale/receipt.tsx
4360
4458
  import { useEffect as useEffect6 } from "react";
4361
- import { Pressable as Pressable28, Text as Text37, View as View58 } from "react-native";
4362
- import { formatMoney as formatMoney13 } from "@tallyui/core";
4459
+ import { Pressable as Pressable29, Text as Text38, View as View59 } from "react-native";
4460
+ import { formatMoney as formatMoney14 } from "@tallyui/core";
4363
4461
  import { buildReceiptData as buildReceiptData3 } from "@tallyui/pos";
4364
4462
 
4365
4463
  // src/sale/print-style.ts
@@ -4379,7 +4477,7 @@ function orderReference(order) {
4379
4477
  }
4380
4478
 
4381
4479
  // src/sale/receipt.tsx
4382
- import { Fragment as Fragment7, jsx as jsx93, jsxs as jsxs52 } from "react/jsx-runtime";
4480
+ import { Fragment as Fragment7, jsx as jsx94, jsxs as jsxs53 } from "react/jsx-runtime";
4383
4481
  var defaultFormatDate = (iso) => new Intl.DateTimeFormat(void 0, { dateStyle: "medium", timeStyle: "short" }).format(new Date(iso));
4384
4482
  function Receipt({
4385
4483
  order,
@@ -4399,33 +4497,33 @@ function Receipt({
4399
4497
  cashier,
4400
4498
  register: registerId
4401
4499
  });
4402
- const money = (amount) => formatMoney13({ amount, currency: receipt.currency }) ?? "";
4403
- const row = (label, amount, bold = false, key) => /* @__PURE__ */ jsxs52(View58, { accessibilityLabel: `${label}: ${amount}`, className: "flex-row justify-between gap-4", children: [
4404
- /* @__PURE__ */ jsx93(Text37, { className: `text-foreground ${bold ? "font-semibold" : ""}`, children: label }),
4405
- /* @__PURE__ */ jsx93(Text37, { className: `text-right text-foreground ${bold ? "font-semibold" : ""}`, children: amount })
4500
+ const money = (amount) => formatMoney14({ amount, currency: receipt.currency }) ?? "";
4501
+ const row = (label, amount, bold = false, key) => /* @__PURE__ */ jsxs53(View59, { accessibilityLabel: `${label}: ${amount}`, className: "flex-row justify-between gap-4", children: [
4502
+ /* @__PURE__ */ jsx94(Text38, { className: `text-foreground ${bold ? "font-semibold" : ""}`, children: label }),
4503
+ /* @__PURE__ */ jsx94(Text38, { className: `text-right text-foreground ${bold ? "font-semibold" : ""}`, children: amount })
4406
4504
  ] }, key);
4407
4505
  const { totals } = receipt;
4408
4506
  const lineDiscountMinor = totals.discountMinor - receipt.orderDiscountMinor;
4409
4507
  const taxRows = totals.taxLines.map((line, index) => row(`${totals.taxInclusive ? "incl. " : ""}${taxLabel(line.ratePpm)}`, money(line.amountMinor), false, index));
4410
- return /* @__PURE__ */ jsxs52(Fragment7, { children: [
4411
- topInset > 0 ? /* @__PURE__ */ jsx93(View58, { dataSet: { print: "hide" }, style: { height: topInset, flexShrink: 0 } }) : null,
4412
- /* @__PURE__ */ jsxs52(View58, { className: "w-full max-w-md self-center gap-3 p-4 bg-card", children: [
4413
- /* @__PURE__ */ jsx93(Text37, { className: "text-lg font-semibold text-foreground", children: receipt.header.storeName }),
4414
- receipt.header.storeAddress ? /* @__PURE__ */ jsx93(Text37, { className: "text-muted-foreground", children: receipt.header.storeAddress }) : null,
4415
- /* @__PURE__ */ jsx93(Text37, { testID: "receipt-order", className: "text-foreground", children: posOrder ? `Order ${orderReference(posOrder)}` : `Order ${receipt.header.orderNumber.slice(-8)} (draft)` }),
4416
- /* @__PURE__ */ jsx93(Text37, { className: "text-muted-foreground", children: formatDate(posOrder?.createdAt ?? receipt.header.date) }),
4417
- /* @__PURE__ */ jsxs52(Text37, { className: "text-muted-foreground", children: [
4508
+ return /* @__PURE__ */ jsxs53(Fragment7, { children: [
4509
+ topInset > 0 ? /* @__PURE__ */ jsx94(View59, { dataSet: { print: "hide" }, style: { height: topInset, flexShrink: 0 } }) : null,
4510
+ /* @__PURE__ */ jsxs53(View59, { className: "w-full max-w-md self-center gap-3 p-4 bg-card", children: [
4511
+ /* @__PURE__ */ jsx94(Text38, { className: "text-lg font-semibold text-foreground", children: receipt.header.storeName }),
4512
+ receipt.header.storeAddress ? /* @__PURE__ */ jsx94(Text38, { className: "text-muted-foreground", children: receipt.header.storeAddress }) : null,
4513
+ /* @__PURE__ */ jsx94(Text38, { testID: "receipt-order", className: "text-foreground", children: posOrder ? `Order ${orderReference(posOrder)}` : `Order ${receipt.header.orderNumber.slice(-8)} (draft)` }),
4514
+ /* @__PURE__ */ jsx94(Text38, { className: "text-muted-foreground", children: formatDate(posOrder?.createdAt ?? receipt.header.date) }),
4515
+ /* @__PURE__ */ jsxs53(Text38, { className: "text-muted-foreground", children: [
4418
4516
  "Cashier: ",
4419
4517
  receipt.header.cashier
4420
4518
  ] }),
4421
- receipt.header.customer && /* @__PURE__ */ jsxs52(Text37, { className: "text-muted-foreground", children: [
4519
+ receipt.header.customer && /* @__PURE__ */ jsxs53(Text38, { className: "text-muted-foreground", children: [
4422
4520
  "Customer: ",
4423
4521
  receipt.header.customer
4424
4522
  ] }),
4425
- receipt.lineItems.map((line, index) => /* @__PURE__ */ jsxs52(View58, { children: [
4426
- /* @__PURE__ */ jsx93(Text37, { className: "text-foreground", children: line.name }),
4523
+ receipt.lineItems.map((line, index) => /* @__PURE__ */ jsxs53(View59, { children: [
4524
+ /* @__PURE__ */ jsx94(Text38, { className: "text-foreground", children: line.name }),
4427
4525
  row(`${line.quantity} \xD7 ${money(line.unitPriceMinor)}`, money(line.displayAmountMinor)),
4428
- line.displayDiscounts.map((discount, i) => /* @__PURE__ */ jsx93(View58, { className: "pl-4", children: row(`${discountLabel(
4526
+ line.displayDiscounts.map((discount, i) => /* @__PURE__ */ jsx94(View59, { className: "pl-4", children: row(`${discountLabel(
4429
4527
  order.lineItems[index].discounts[i],
4430
4528
  receipt.currency
4431
4529
  )} off`, `\u2212${money(discount.amountMinor)}`) }, i))
@@ -4442,19 +4540,19 @@ function Receipt({
4442
4540
  index
4443
4541
  )),
4444
4542
  row("Change", money(receipt.changeDueMinor)),
4445
- /* @__PURE__ */ jsxs52(View58, { dataSet: { print: "hide" }, className: "flex-row gap-4", children: [
4446
- /* @__PURE__ */ jsx93(Pressable28, { accessibilityRole: "button", onPress: () => {
4543
+ /* @__PURE__ */ jsxs53(View59, { dataSet: { print: "hide" }, className: "flex-row gap-4", children: [
4544
+ /* @__PURE__ */ jsx94(Pressable29, { accessibilityRole: "button", onPress: () => {
4447
4545
  if (typeof window !== "undefined" && typeof window.print === "function") window.print();
4448
- }, className: "rounded-md border border-border bg-card px-4 py-3", children: /* @__PURE__ */ jsx93(Text37, { className: "text-center text-foreground", children: "Print receipt" }) }),
4449
- /* @__PURE__ */ jsx93(Pressable28, { accessibilityRole: "button", onPress: newSale, className: "rounded-md bg-primary px-4 py-3", children: /* @__PURE__ */ jsx93(Text37, { className: "text-center font-semibold text-primary-foreground", children: "New sale" }) })
4546
+ }, className: "rounded-md border border-border bg-card px-4 py-3", children: /* @__PURE__ */ jsx94(Text38, { className: "text-center text-foreground", children: "Print receipt" }) }),
4547
+ /* @__PURE__ */ jsx94(Pressable29, { accessibilityRole: "button", onPress: newSale, className: "rounded-md bg-primary px-4 py-3", children: /* @__PURE__ */ jsx94(Text38, { className: "text-center font-semibold text-primary-foreground", children: "New sale" }) })
4450
4548
  ] })
4451
4549
  ] })
4452
4550
  ] });
4453
4551
  }
4454
4552
 
4455
4553
  // src/sale/sync-status.tsx
4456
- import { useEffect as useEffect7, useRef as useRef6, useState as useState18 } from "react";
4457
- import { AccessibilityInfo as AccessibilityInfo2, Platform as Platform3, Text as Text38, View as View59 } from "react-native";
4554
+ import { useEffect as useEffect7, useRef as useRef6, useState as useState20 } from "react";
4555
+ import { AccessibilityInfo as AccessibilityInfo2, Platform as Platform3, Text as Text39, View as View60 } from "react-native";
4458
4556
 
4459
4557
  // src/sale/since-text.ts
4460
4558
  function sinceText(clock) {
@@ -4463,7 +4561,7 @@ function sinceText(clock) {
4463
4561
  }
4464
4562
 
4465
4563
  // src/sale/sync-status.tsx
4466
- import { Fragment as Fragment8, jsx as jsx94, jsxs as jsxs53 } from "react/jsx-runtime";
4564
+ import { Fragment as Fragment8, jsx as jsx95, jsxs as jsxs54 } from "react/jsx-runtime";
4467
4565
  var PULL_NOTICE_TEXT = {
4468
4566
  unauthorized: {
4469
4567
  line: () => "Products aren't updating: this till needs to sign in to the online store again.",
@@ -4515,7 +4613,7 @@ function useAnnounceOnIos(...texts) {
4515
4613
  function SyncStatus({ state, registerState, pluginName = "the POS plugin", pullNotice }) {
4516
4614
  const updates = registerState?.pending ?? 0;
4517
4615
  const outbox = state.pending === 0 && registerState?.pending ? registerState : state;
4518
- const [now, setNow] = useState18(Date.now);
4616
+ const [now, setNow] = useState20(Date.now);
4519
4617
  useEffect7(() => {
4520
4618
  setNow(Date.now());
4521
4619
  if (!outbox.nextAttemptAt) return;
@@ -4539,24 +4637,24 @@ function SyncStatus({ state, registerState, pluginName = "the POS plugin", pullN
4539
4637
  const notice = pullNotice && text && { line: text.line(pluginName), detail: text.detail(pullNotice, pluginName) };
4540
4638
  useAnnounceOnIos(notice?.line, spoken);
4541
4639
  const oneDetail = pullNotice?.code === "missing_plugin" && !!backendMissing;
4542
- return /* @__PURE__ */ jsxs53(View59, { children: [
4543
- notice ? /* @__PURE__ */ jsxs53(Fragment8, { children: [
4544
- /* @__PURE__ */ jsx94(Text38, { accessibilityLiveRegion: "polite", className: "px-4 py-2 text-xs text-muted-foreground", children: notice.line }),
4545
- oneDetail ? null : /* @__PURE__ */ jsx94(Text38, { className: "px-4 pb-2 text-xs text-muted-foreground", children: notice.detail })
4640
+ return /* @__PURE__ */ jsxs54(View60, { children: [
4641
+ notice ? /* @__PURE__ */ jsxs54(Fragment8, { children: [
4642
+ /* @__PURE__ */ jsx95(Text39, { accessibilityLiveRegion: "polite", className: "px-4 py-2 text-xs text-muted-foreground", children: notice.line }),
4643
+ oneDetail ? null : /* @__PURE__ */ jsx95(Text39, { className: "px-4 pb-2 text-xs text-muted-foreground", children: notice.detail })
4546
4644
  ] }) : null,
4547
- /* @__PURE__ */ jsx94(Text38, { accessibilityLabel: spoken, accessibilityLiveRegion: "polite", className: "px-4 py-2 text-xs text-muted-foreground", children: spoken }),
4548
- doing ? /* @__PURE__ */ jsx94(Text38, { className: "px-4 pb-2 text-xs text-muted-foreground", children: doing }) : null,
4549
- refused ? /* @__PURE__ */ jsx94(Text38, { className: "px-4 pb-2 text-xs text-muted-foreground", children: REFUSED_DETAIL }) : null,
4550
- oneDetail && notice ? /* @__PURE__ */ jsx94(Text38, { className: "px-4 pb-2 text-xs text-muted-foreground", children: notice.detail }) : backendMissing ? /* @__PURE__ */ jsx94(Text38, { className: "px-4 pb-2 text-xs text-muted-foreground", children: BACKEND_MISSING_DETAIL.replace("{pluginName}", () => pluginName).replace("{lastTime}", () => upToDate ? " the last time it checked" : "") }) : null
4645
+ /* @__PURE__ */ jsx95(Text39, { accessibilityLabel: spoken, accessibilityLiveRegion: "polite", className: "px-4 py-2 text-xs text-muted-foreground", children: spoken }),
4646
+ doing ? /* @__PURE__ */ jsx95(Text39, { className: "px-4 pb-2 text-xs text-muted-foreground", children: doing }) : null,
4647
+ refused ? /* @__PURE__ */ jsx95(Text39, { className: "px-4 pb-2 text-xs text-muted-foreground", children: REFUSED_DETAIL }) : null,
4648
+ oneDetail && notice ? /* @__PURE__ */ jsx95(Text39, { className: "px-4 pb-2 text-xs text-muted-foreground", children: notice.detail }) : backendMissing ? /* @__PURE__ */ jsx95(Text39, { className: "px-4 pb-2 text-xs text-muted-foreground", children: BACKEND_MISSING_DETAIL.replace("{pluginName}", () => pluginName).replace("{lastTime}", () => upToDate ? " the last time it checked" : "") }) : null
4551
4649
  ] });
4552
4650
  }
4553
4651
 
4554
4652
  // src/sale/orders-list.tsx
4555
- import { useEffect as useEffect8, useRef as useRef7, useState as useState19 } from "react";
4556
- import { Pressable as Pressable29, ScrollView as ScrollView13, Text as Text39, View as View60 } from "react-native";
4557
- import { formatMoney as formatMoney14, knownWarnings } from "@tallyui/core";
4653
+ import { useEffect as useEffect8, useRef as useRef7, useState as useState21 } from "react";
4654
+ import { Pressable as Pressable30, ScrollView as ScrollView13, Text as Text40, View as View61 } from "react-native";
4655
+ import { formatMoney as formatMoney15, knownWarnings } from "@tallyui/core";
4558
4656
  import { needsAttention } from "@tallyui/pos";
4559
- import { jsx as jsx95, jsxs as jsxs54 } from "react/jsx-runtime";
4657
+ import { jsx as jsx96, jsxs as jsxs55 } from "react/jsx-runtime";
4560
4658
  var STATUS_LABEL = { pending: "Waiting to sync", applied: "Synced", rejected: "Not accepted" };
4561
4659
  var FIGURE_LABELS = /* @__PURE__ */ new Map([["subtotalMinor", "Subtotal"], ["taxMinor", "Tax"], ["discountMinor", "Discount"]]);
4562
4660
  var REFUSAL_SENTENCES = /* @__PURE__ */ new Map([
@@ -4580,26 +4678,26 @@ function defaultFormatDate2(iso) {
4580
4678
  }
4581
4679
  function OrdersList({ orders, onRetry, formatDate = defaultFormatDate2, footer, stuck }) {
4582
4680
  const retrying = useRef7(/* @__PURE__ */ new Set());
4583
- const [retryingIds, setRetryingIds] = useState19(/* @__PURE__ */ new Set());
4584
- const [expanded, setExpanded] = useState19(/* @__PURE__ */ new Set());
4681
+ const [retryingIds, setRetryingIds] = useState21(/* @__PURE__ */ new Set());
4682
+ const [expanded, setExpanded] = useState21(/* @__PURE__ */ new Set());
4585
4683
  useEffect8(() => {
4586
4684
  for (const id of retrying.current) {
4587
4685
  if (!orders.some((order) => order.id === id && order.syncStatus === "rejected")) retrying.current.delete(id);
4588
4686
  }
4589
4687
  setRetryingIds(new Set(retrying.current));
4590
4688
  }, [orders]);
4591
- return /* @__PURE__ */ jsxs54(ScrollView13, { className: "flex-1 bg-background p-4", children: [
4592
- [{ title: "Needs attention", orders: needsAttention(orders, { stuckCommandIds: stuck?.commandIds }) }, { title: "Recent", orders }].filter((section) => section.title === "Recent" || section.orders.length > 0).map((section) => /* @__PURE__ */ jsxs54(View60, { className: "mb-6 gap-3", children: [
4593
- /* @__PURE__ */ jsx95(Text39, { accessibilityRole: "header", className: "text-xl font-semibold text-foreground", children: section.title }),
4594
- section.title === "Recent" && orders.length === 0 ? /* @__PURE__ */ jsx95(Text39, { testID: "orders-empty", className: "text-muted-foreground", children: "No sales yet. Completed sales appear here." }) : null,
4689
+ return /* @__PURE__ */ jsxs55(ScrollView13, { className: "flex-1 bg-background p-4", children: [
4690
+ [{ title: "Needs attention", orders: needsAttention(orders, { stuckCommandIds: stuck?.commandIds }) }, { title: "Recent", orders }].filter((section) => section.title === "Recent" || section.orders.length > 0).map((section) => /* @__PURE__ */ jsxs55(View61, { className: "mb-6 gap-3", children: [
4691
+ /* @__PURE__ */ jsx96(Text40, { accessibilityRole: "header", className: "text-xl font-semibold text-foreground", children: section.title }),
4692
+ section.title === "Recent" && orders.length === 0 ? /* @__PURE__ */ jsx96(Text40, { testID: "orders-empty", className: "text-muted-foreground", children: "No sales yet. Completed sales appear here." }) : null,
4595
4693
  section.orders.map((order) => {
4596
4694
  const count2 = order.lines.reduce((sum, line) => sum + line.quantity, 0);
4597
4695
  const key = `${section.title}:${order.id}`;
4598
4696
  const isExpanded = expanded.has(key);
4599
4697
  const stuckEntry = order.syncStatus === "pending" ? stuck?.orders.find((entry) => entry.commandId === order.commandId) : void 0;
4600
- return /* @__PURE__ */ jsxs54(View60, { className: "gap-1 rounded-md border border-border bg-card p-3", children: [
4601
- /* @__PURE__ */ jsxs54(
4602
- Pressable29,
4698
+ return /* @__PURE__ */ jsxs55(View61, { className: "gap-1 rounded-md border border-border bg-card p-3", children: [
4699
+ /* @__PURE__ */ jsxs55(
4700
+ Pressable30,
4603
4701
  {
4604
4702
  accessibilityRole: "button",
4605
4703
  "aria-expanded": isExpanded,
@@ -4613,26 +4711,26 @@ function OrdersList({ orders, onRetry, formatDate = defaultFormatDate2, footer,
4613
4711
  return next;
4614
4712
  }),
4615
4713
  children: [
4616
- /* @__PURE__ */ jsx95(Text39, { className: "text-foreground", children: `Order ${orderReference(order)} \xB7 ${count2} ${count2 === 1 ? "item" : "items"}` }),
4617
- /* @__PURE__ */ jsxs54(Text39, { className: "text-muted-foreground", children: [
4714
+ /* @__PURE__ */ jsx96(Text40, { className: "text-foreground", children: `Order ${orderReference(order)} \xB7 ${count2} ${count2 === 1 ? "item" : "items"}` }),
4715
+ /* @__PURE__ */ jsxs55(Text40, { className: "text-muted-foreground", children: [
4618
4716
  formatDate(order.createdAt),
4619
4717
  " \xB7 ",
4620
- formatMoney14({ amount: order.totalMinor, currency: order.currency }),
4718
+ formatMoney15({ amount: order.totalMinor, currency: order.currency }),
4621
4719
  " \xB7 ",
4622
4720
  STATUS_LABEL[order.syncStatus]
4623
4721
  ] })
4624
4722
  ]
4625
4723
  }
4626
4724
  ),
4627
- isExpanded ? /* @__PURE__ */ jsxs54(View60, { testID: `order-detail-${order.id}`, className: "mt-1 gap-1 border-t border-border pt-2", children: [
4628
- order.lines.map((line) => /* @__PURE__ */ jsx95(Text39, { className: "text-foreground", children: `${line.quantity} \xD7 ${line.name}` }, line.id)),
4629
- order.payments.map((payment) => /* @__PURE__ */ jsx95(Text39, { className: "text-muted-foreground", children: `${payment.method === "cash" ? "Cash" : "Card terminal"} ${formatMoney14({ amount: payment.amountMinor, currency: order.currency })}${payment.reference ? ` \xB7 ${payment.reference}` : ""}` }, payment.id))
4725
+ isExpanded ? /* @__PURE__ */ jsxs55(View61, { testID: `order-detail-${order.id}`, className: "mt-1 gap-1 border-t border-border pt-2", children: [
4726
+ order.lines.map((line) => /* @__PURE__ */ jsx96(Text40, { className: "text-foreground", children: `${line.quantity} \xD7 ${line.name}` }, line.id)),
4727
+ order.payments.map((payment) => /* @__PURE__ */ jsx96(Text40, { className: "text-muted-foreground", children: `${payment.method === "cash" ? "Cash" : "Card terminal"} ${formatMoney15({ amount: payment.amountMinor, currency: order.currency })}${payment.reference ? ` \xB7 ${payment.reference}` : ""}` }, payment.id))
4630
4728
  ] }) : null,
4631
- stuckEntry ? /* @__PURE__ */ jsx95(Text39, { className: "text-destructive", children: `Hasn't reached the online store since ${sinceText(stuckEntry)}.` }) : null,
4632
- order.syncStatus === "rejected" ? /* @__PURE__ */ jsx95(Text39, { className: "text-destructive", children: refusalSentence(order.error?.code) }) : null,
4633
- order.lateSessionId !== void 0 ? /* @__PURE__ */ jsx95(Text39, { className: "text-foreground", children: "Taken after the register closed. It is not in that register's closure." }) : null,
4634
- order.localWarnings?.map((warning, index) => /* @__PURE__ */ jsx95(Text39, { className: "text-foreground", children: warning.code === "customer_omitted" ? `The customer's ${warning.field} couldn't be sent to the store, so the order isn't linked to them.` : "The terminal's payment reference couldn't be kept; the payment is recorded without it." }, index)),
4635
- section.title === "Needs attention" && order.syncStatus === "rejected" && order.error?.code !== "idempotency_mismatch" ? /* @__PURE__ */ jsx95(Pressable29, { accessibilityRole: "button", disabled: retryingIds.has(order.id), onPress: async () => {
4729
+ stuckEntry ? /* @__PURE__ */ jsx96(Text40, { className: "text-destructive", children: `Hasn't reached the online store since ${sinceText(stuckEntry)}.` }) : null,
4730
+ order.syncStatus === "rejected" ? /* @__PURE__ */ jsx96(Text40, { className: "text-destructive", children: refusalSentence(order.error?.code) }) : null,
4731
+ order.lateSessionId !== void 0 ? /* @__PURE__ */ jsx96(Text40, { className: "text-foreground", children: "Taken after the register closed. It is not in that register's closure." }) : null,
4732
+ order.localWarnings?.map((warning, index) => /* @__PURE__ */ jsx96(Text40, { className: "text-foreground", children: warning.code === "customer_omitted" ? `The customer's ${warning.field} couldn't be sent to the store, so the order isn't linked to them.` : "The terminal's payment reference couldn't be kept; the payment is recorded without it." }, index)),
4733
+ section.title === "Needs attention" && order.syncStatus === "rejected" && order.error?.code !== "idempotency_mismatch" ? /* @__PURE__ */ jsx96(Pressable30, { accessibilityRole: "button", disabled: retryingIds.has(order.id), onPress: async () => {
4636
4734
  if (retrying.current.has(order.id)) return;
4637
4735
  retrying.current.add(order.id);
4638
4736
  setRetryingIds(new Set(retrying.current));
@@ -4640,8 +4738,8 @@ function OrdersList({ orders, onRetry, formatDate = defaultFormatDate2, footer,
4640
4738
  retrying.current.delete(order.id);
4641
4739
  setRetryingIds(new Set(retrying.current));
4642
4740
  }
4643
- }, className: "rounded-md bg-primary px-4 py-2", children: /* @__PURE__ */ jsx95(Text39, { className: "text-center font-semibold text-primary-foreground", children: "Retry" }) }) : null,
4644
- knownWarnings(order.warnings).map((warning, index) => /* @__PURE__ */ jsx95(View60, { className: "border-l-4 border-warning pl-2", children: /* @__PURE__ */ jsx95(Text39, { className: "text-foreground", children: warning.code === "insufficient_stock" ? `Stock short by ${warning.quantity} for ${order.lines.find((line) => line.variantId === warning.variantId)?.name}` : warning.code === "tax_rate_mismatch" ? `Tax at ${(warning.ratePpm / 1e4).toLocaleString(void 0, { maximumFractionDigits: 4 })}%: store ${formatMoney14({ amount: warning.serverMinor, currency: order.currency })} vs POS ${formatMoney14({ amount: warning.expectedMinor, currency: order.currency })}` : warning.code === "customer_ignored" ? `The online store didn't recognise the customer on this sale, so it was saved as a guest sale. Customer id: ${warning.customerId}.` : warning.code === "figures_mismatch" ? `The online store worked out different figures for this sale. ${warning.fields.map(({ field, tillMinor, serverMinor }) => `${FIGURE_LABELS.get(field) ?? field}: till ${formatMoney14({ amount: tillMinor, currency: order.currency })}, store ${formatMoney14({ amount: serverMinor, currency: order.currency })}.`).join(" ")}` : warning.bridgeMinor !== void 0 ? `Store calculated ${formatMoney14({ amount: warning.serverMinor, currency: order.currency })}; a rounding line of ${warning.bridgeMinor > 0 ? "+" : ""}${formatMoney14({ amount: warning.bridgeMinor, currency: order.currency })} brought it to ${formatMoney14({ amount: warning.expectedMinor, currency: order.currency })}` : `Store total ${formatMoney14({ amount: warning.serverMinor, currency: order.currency })} vs POS ${formatMoney14({ amount: warning.expectedMinor, currency: order.currency })}` }) }, index))
4741
+ }, className: "rounded-md bg-primary px-4 py-2", children: /* @__PURE__ */ jsx96(Text40, { className: "text-center font-semibold text-primary-foreground", children: "Retry" }) }) : null,
4742
+ knownWarnings(order.warnings).map((warning, index) => /* @__PURE__ */ jsx96(View61, { className: "border-l-4 border-warning pl-2", children: /* @__PURE__ */ jsx96(Text40, { className: "text-foreground", children: warning.code === "insufficient_stock" ? `Stock short by ${warning.quantity} for ${order.lines.find((line) => line.variantId === warning.variantId)?.name}` : warning.code === "tax_rate_mismatch" ? `Tax at ${(warning.ratePpm / 1e4).toLocaleString(void 0, { maximumFractionDigits: 4 })}%: store ${formatMoney15({ amount: warning.serverMinor, currency: order.currency })} vs POS ${formatMoney15({ amount: warning.expectedMinor, currency: order.currency })}` : warning.code === "customer_ignored" ? `The online store didn't recognise the customer on this sale, so it was saved as a guest sale. Customer id: ${warning.customerId}.` : warning.code === "figures_mismatch" ? `The online store worked out different figures for this sale. ${warning.fields.map(({ field, tillMinor, serverMinor }) => `${FIGURE_LABELS.get(field) ?? field}: till ${formatMoney15({ amount: tillMinor, currency: order.currency })}, store ${formatMoney15({ amount: serverMinor, currency: order.currency })}.`).join(" ")}` : warning.bridgeMinor !== void 0 ? `Store calculated ${formatMoney15({ amount: warning.serverMinor, currency: order.currency })}; a rounding line of ${warning.bridgeMinor > 0 ? "+" : ""}${formatMoney15({ amount: warning.bridgeMinor, currency: order.currency })} brought it to ${formatMoney15({ amount: warning.expectedMinor, currency: order.currency })}` : `Store total ${formatMoney15({ amount: warning.serverMinor, currency: order.currency })} vs POS ${formatMoney15({ amount: warning.expectedMinor, currency: order.currency })}` }) }, index))
4645
4743
  ] }, order.id);
4646
4744
  })
4647
4745
  ] }, section.title)),
@@ -4649,11 +4747,103 @@ function OrdersList({ orders, onRetry, formatDate = defaultFormatDate2, footer,
4649
4747
  ] });
4650
4748
  }
4651
4749
 
4750
+ // src/sale/parked-sales.tsx
4751
+ import { useState as useState22 } from "react";
4752
+ import { ScrollView as ScrollView14, useWindowDimensions as useWindowDimensions3, View as View62 } from "react-native";
4753
+ import { formatMoney as formatMoney16 } from "@tallyui/core";
4754
+ import { Fragment as Fragment9, jsx as jsx97, jsxs as jsxs56 } from "react/jsx-runtime";
4755
+ function ParkedSales({ sale, parked, onDiscard, currency, open, onOpenChange, hour12 }) {
4756
+ const { height: windowHeight } = useWindowDimensions3();
4757
+ const maxHeight = Math.max(280, windowHeight - 64);
4758
+ const [confirming, setConfirming] = useState22(null);
4759
+ const [error, setError] = useState22("");
4760
+ const attempt = async (action) => {
4761
+ setError("");
4762
+ try {
4763
+ await action();
4764
+ } catch (e) {
4765
+ setError(String(e));
4766
+ }
4767
+ };
4768
+ return /* @__PURE__ */ jsx97(Dialog, { open, onOpenChange, children: /* @__PURE__ */ jsxs56(DialogContent, { testID: "parked-sales", className: "flex-col overflow-hidden", style: { maxHeight }, children: [
4769
+ /* @__PURE__ */ jsxs56(View62, { className: "flex-row items-center justify-between gap-2", children: [
4770
+ /* @__PURE__ */ jsx97(DialogTitle, { children: "Parked sales" }),
4771
+ /* @__PURE__ */ jsx97(DialogClose, { asChild: true, children: /* @__PURE__ */ jsx97(IconButton, { variant: "ghost", size: "sm", testID: "parked-sales-dismiss", accessibilityLabel: "Close panel", children: /* @__PURE__ */ jsx97(XIcon, { size: 16 }) }) })
4772
+ ] }),
4773
+ /* @__PURE__ */ jsxs56(ScrollView14, { className: "flex-1", contentContainerClassName: "gap-3", children: [
4774
+ /* @__PURE__ */ jsx97(
4775
+ Button,
4776
+ {
4777
+ testID: "parked-sales-park",
4778
+ accessibilityLabel: "Park this sale",
4779
+ disabled: sale.order.lineItems.length === 0,
4780
+ onPress: () => attempt(async () => setError(await sale.park() ?? "")),
4781
+ children: /* @__PURE__ */ jsx97(Text, { children: "Park this sale" })
4782
+ }
4783
+ ),
4784
+ !!error && /* @__PURE__ */ jsx97(Text, { testID: "parked-sales-error", className: "text-destructive", children: error }),
4785
+ parked.length === 0 && /* @__PURE__ */ jsx97(Text, { testID: "parked-sales-empty", children: "No parked sales." }),
4786
+ parked.map((row) => /* @__PURE__ */ jsx97(View62, { testID: `parked-row-${row.id}`, className: "gap-2 rounded-md border border-border p-3", children: confirming === row.id ? /* @__PURE__ */ jsxs56(Fragment9, { children: [
4787
+ /* @__PURE__ */ jsx97(Text, { children: "Discard this parked sale?" }),
4788
+ /* @__PURE__ */ jsxs56(View62, { className: "flex-row gap-2", children: [
4789
+ /* @__PURE__ */ jsx97(
4790
+ Button,
4791
+ {
4792
+ testID: `parked-discard-confirm-${row.id}`,
4793
+ variant: "destructive",
4794
+ onPress: () => attempt(async () => {
4795
+ await onDiscard(row.id);
4796
+ setConfirming(null);
4797
+ }),
4798
+ children: /* @__PURE__ */ jsx97(Text, { children: "Discard" })
4799
+ }
4800
+ ),
4801
+ /* @__PURE__ */ jsx97(Button, { testID: `parked-discard-cancel-${row.id}`, variant: "outline", onPress: () => setConfirming(null), children: /* @__PURE__ */ jsx97(Text, { children: "Cancel" }) })
4802
+ ] })
4803
+ ] }) : /* @__PURE__ */ jsxs56(Fragment9, { children: [
4804
+ /* @__PURE__ */ jsx97(Text, { children: formatStockSyncTime(new Date(row.parkedAt), void 0, hour12) }),
4805
+ /* @__PURE__ */ jsxs56(Text, { children: [
4806
+ row.itemCount,
4807
+ " ",
4808
+ row.itemCount === 1 ? "item" : "items"
4809
+ ] }),
4810
+ /* @__PURE__ */ jsx97(Text, { children: formatMoney16({ amount: row.totalMinor, currency }) }),
4811
+ !!row.customerName && /* @__PURE__ */ jsx97(Text, { children: row.customerName }),
4812
+ /* @__PURE__ */ jsxs56(View62, { className: "flex-row gap-2", children: [
4813
+ /* @__PURE__ */ jsx97(
4814
+ Button,
4815
+ {
4816
+ testID: `parked-resume-${row.id}`,
4817
+ accessibilityLabel: "Resume parked sale",
4818
+ onPress: () => attempt(async () => {
4819
+ const refusal = await sale.resume(row.id);
4820
+ if (refusal === null) onOpenChange(false);
4821
+ else setError(refusal);
4822
+ }),
4823
+ children: /* @__PURE__ */ jsx97(Text, { children: "Resume" })
4824
+ }
4825
+ ),
4826
+ /* @__PURE__ */ jsx97(
4827
+ Button,
4828
+ {
4829
+ testID: `parked-discard-${row.id}`,
4830
+ accessibilityLabel: "Discard parked sale",
4831
+ variant: "outline",
4832
+ onPress: () => setConfirming(row.id),
4833
+ children: /* @__PURE__ */ jsx97(Text, { children: "Discard" })
4834
+ }
4835
+ )
4836
+ ] })
4837
+ ] }) }, row.id))
4838
+ ] })
4839
+ ] }) });
4840
+ }
4841
+
4652
4842
  // src/layout/pos-layout.tsx
4653
- import { useState as useState20 } from "react";
4654
- import { Pressable as Pressable30, Text as Text40, View as View61, useWindowDimensions as useWindowDimensions3 } from "react-native";
4843
+ import { useState as useState23 } from "react";
4844
+ import { Pressable as Pressable31, Text as Text41, View as View63, useWindowDimensions as useWindowDimensions4 } from "react-native";
4655
4845
  import { cn as cn80 } from "@tallyui/theme";
4656
- import { Fragment as Fragment9, jsx as jsx96, jsxs as jsxs55 } from "react/jsx-runtime";
4846
+ import { Fragment as Fragment10, jsx as jsx98, jsxs as jsxs57 } from "react/jsx-runtime";
4657
4847
  function POSLayout({
4658
4848
  browseSlot,
4659
4849
  cartSlot,
@@ -4663,42 +4853,42 @@ function POSLayout({
4663
4853
  className,
4664
4854
  ...viewProps
4665
4855
  }) {
4666
- const { width } = useWindowDimensions3();
4856
+ const { width } = useWindowDimensions4();
4667
4857
  const layout = layoutProp ?? (width >= breakpoint ? "split" : "stacked");
4668
- const [activeTab, setActiveTab] = useState20("browse");
4669
- return /* @__PURE__ */ jsxs55(View61, { className: cn80("flex-1 bg-bg", className), ...viewProps, children: [
4670
- headerSlot && /* @__PURE__ */ jsx96(View61, { className: "border-b border-border", children: headerSlot }),
4671
- layout === "split" ? /* @__PURE__ */ jsxs55(View61, { className: "flex-1 flex-row", children: [
4672
- /* @__PURE__ */ jsx96(View61, { className: "flex-[3]", children: browseSlot }),
4673
- /* @__PURE__ */ jsx96(View61, { className: "flex-[2] border-l border-border", children: cartSlot })
4674
- ] }) : /* @__PURE__ */ jsxs55(Fragment9, { children: [
4675
- /* @__PURE__ */ jsxs55(View61, { className: "flex-row border-b border-border", children: [
4676
- /* @__PURE__ */ jsx96(
4677
- Pressable30,
4858
+ const [activeTab, setActiveTab] = useState23("browse");
4859
+ return /* @__PURE__ */ jsxs57(View63, { className: cn80("flex-1 bg-bg", className), ...viewProps, children: [
4860
+ headerSlot && /* @__PURE__ */ jsx98(View63, { className: "border-b border-border", children: headerSlot }),
4861
+ layout === "split" ? /* @__PURE__ */ jsxs57(View63, { className: "flex-1 flex-row", children: [
4862
+ /* @__PURE__ */ jsx98(View63, { className: "flex-[3]", children: browseSlot }),
4863
+ /* @__PURE__ */ jsx98(View63, { className: "flex-[2] border-l border-border", children: cartSlot })
4864
+ ] }) : /* @__PURE__ */ jsxs57(Fragment10, { children: [
4865
+ /* @__PURE__ */ jsxs57(View63, { className: "flex-row border-b border-border", children: [
4866
+ /* @__PURE__ */ jsx98(
4867
+ Pressable31,
4678
4868
  {
4679
4869
  onPress: () => setActiveTab("browse"),
4680
4870
  className: cn80("flex-1 py-3", activeTab === "browse" && "border-b-2 border-primary"),
4681
- children: /* @__PURE__ */ jsx96(Text40, { className: cn80("text-center text-sm font-semibold", activeTab === "browse" ? "text-primary" : "text-muted-foreground"), children: "Browse" })
4871
+ children: /* @__PURE__ */ jsx98(Text41, { className: cn80("text-center text-sm font-semibold", activeTab === "browse" ? "text-primary" : "text-muted-foreground"), children: "Browse" })
4682
4872
  }
4683
4873
  ),
4684
- /* @__PURE__ */ jsx96(
4685
- Pressable30,
4874
+ /* @__PURE__ */ jsx98(
4875
+ Pressable31,
4686
4876
  {
4687
4877
  onPress: () => setActiveTab("cart"),
4688
4878
  className: cn80("flex-1 py-3", activeTab === "cart" && "border-b-2 border-primary"),
4689
- children: /* @__PURE__ */ jsx96(Text40, { className: cn80("text-center text-sm font-semibold", activeTab === "cart" ? "text-primary" : "text-muted-foreground"), children: "Cart" })
4879
+ children: /* @__PURE__ */ jsx98(Text41, { className: cn80("text-center text-sm font-semibold", activeTab === "cart" ? "text-primary" : "text-muted-foreground"), children: "Cart" })
4690
4880
  }
4691
4881
  )
4692
4882
  ] }),
4693
- /* @__PURE__ */ jsx96(View61, { className: "flex-1", children: activeTab === "browse" ? browseSlot : cartSlot })
4883
+ /* @__PURE__ */ jsx98(View63, { className: "flex-1", children: activeTab === "browse" ? browseSlot : cartSlot })
4694
4884
  ] })
4695
4885
  ] });
4696
4886
  }
4697
4887
 
4698
4888
  // src/layout/checkout-layout.tsx
4699
- import { ScrollView as ScrollView14, View as View62, useWindowDimensions as useWindowDimensions4 } from "react-native";
4889
+ import { ScrollView as ScrollView15, View as View64, useWindowDimensions as useWindowDimensions5 } from "react-native";
4700
4890
  import { cn as cn81 } from "@tallyui/theme";
4701
- import { jsx as jsx97, jsxs as jsxs56 } from "react/jsx-runtime";
4891
+ import { jsx as jsx99, jsxs as jsxs58 } from "react/jsx-runtime";
4702
4892
  function CheckoutLayout({
4703
4893
  summarySlot,
4704
4894
  paymentSlot,
@@ -4708,14 +4898,14 @@ function CheckoutLayout({
4708
4898
  className,
4709
4899
  ...viewProps
4710
4900
  }) {
4711
- const { width } = useWindowDimensions4();
4901
+ const { width } = useWindowDimensions5();
4712
4902
  const layout = layoutProp ?? (width >= breakpoint ? "split" : "stacked");
4713
- return /* @__PURE__ */ jsxs56(View62, { className: cn81("flex-1 bg-bg", className), ...viewProps, children: [
4714
- headerSlot && /* @__PURE__ */ jsx97(View62, { className: "border-b border-border", children: headerSlot }),
4715
- layout === "split" ? /* @__PURE__ */ jsxs56(View62, { className: "flex-1 flex-row", children: [
4716
- /* @__PURE__ */ jsx97(View62, { className: "flex-1 border-r border-border", children: summarySlot }),
4717
- /* @__PURE__ */ jsx97(View62, { className: "flex-1", children: paymentSlot })
4718
- ] }) : /* @__PURE__ */ jsx97(ScrollView14, { className: "flex-1", children: /* @__PURE__ */ jsxs56(View62, { className: "gap-4 p-4", children: [
4903
+ return /* @__PURE__ */ jsxs58(View64, { className: cn81("flex-1 bg-bg", className), ...viewProps, children: [
4904
+ headerSlot && /* @__PURE__ */ jsx99(View64, { className: "border-b border-border", children: headerSlot }),
4905
+ layout === "split" ? /* @__PURE__ */ jsxs58(View64, { className: "flex-1 flex-row", children: [
4906
+ /* @__PURE__ */ jsx99(View64, { className: "flex-1 border-r border-border", children: summarySlot }),
4907
+ /* @__PURE__ */ jsx99(View64, { className: "flex-1", children: paymentSlot })
4908
+ ] }) : /* @__PURE__ */ jsx99(ScrollView15, { className: "flex-1", children: /* @__PURE__ */ jsxs58(View64, { className: "gap-4 p-4", children: [
4719
4909
  summarySlot,
4720
4910
  paymentSlot
4721
4911
  ] }) })
@@ -4723,10 +4913,10 @@ function CheckoutLayout({
4723
4913
  }
4724
4914
 
4725
4915
  // src/layout/settings-layout.tsx
4726
- import { useState as useState21 } from "react";
4727
- import { Pressable as Pressable31, Text as Text41, View as View63, useWindowDimensions as useWindowDimensions5 } from "react-native";
4916
+ import { useState as useState24 } from "react";
4917
+ import { Pressable as Pressable32, Text as Text42, View as View65, useWindowDimensions as useWindowDimensions6 } from "react-native";
4728
4918
  import { cn as cn82 } from "@tallyui/theme";
4729
- import { jsx as jsx98, jsxs as jsxs57 } from "react/jsx-runtime";
4919
+ import { jsx as jsx100, jsxs as jsxs59 } from "react/jsx-runtime";
4730
4920
  function SettingsLayout({
4731
4921
  navSlot,
4732
4922
  contentSlot,
@@ -4736,28 +4926,28 @@ function SettingsLayout({
4736
4926
  className,
4737
4927
  ...viewProps
4738
4928
  }) {
4739
- const { width } = useWindowDimensions5();
4929
+ const { width } = useWindowDimensions6();
4740
4930
  const layout = layoutProp ?? (width >= breakpoint ? "split" : "stacked");
4741
- const [showNav, setShowNav] = useState21(false);
4742
- return /* @__PURE__ */ jsxs57(View63, { className: cn82("flex-1 bg-bg", className), ...viewProps, children: [
4743
- headerSlot && /* @__PURE__ */ jsx98(View63, { className: "border-b border-border", children: headerSlot }),
4744
- layout === "split" ? /* @__PURE__ */ jsxs57(View63, { className: "flex-1 flex-row", children: [
4745
- /* @__PURE__ */ jsx98(View63, { className: "w-64 border-r border-border", children: navSlot }),
4746
- /* @__PURE__ */ jsx98(View63, { className: "flex-1", children: contentSlot })
4747
- ] }) : /* @__PURE__ */ jsx98(View63, { className: "flex-1", children: showNav ? /* @__PURE__ */ jsxs57(View63, { className: "flex-1", children: [
4931
+ const [showNav, setShowNav] = useState24(false);
4932
+ return /* @__PURE__ */ jsxs59(View65, { className: cn82("flex-1 bg-bg", className), ...viewProps, children: [
4933
+ headerSlot && /* @__PURE__ */ jsx100(View65, { className: "border-b border-border", children: headerSlot }),
4934
+ layout === "split" ? /* @__PURE__ */ jsxs59(View65, { className: "flex-1 flex-row", children: [
4935
+ /* @__PURE__ */ jsx100(View65, { className: "w-64 border-r border-border", children: navSlot }),
4936
+ /* @__PURE__ */ jsx100(View65, { className: "flex-1", children: contentSlot })
4937
+ ] }) : /* @__PURE__ */ jsx100(View65, { className: "flex-1", children: showNav ? /* @__PURE__ */ jsxs59(View65, { className: "flex-1", children: [
4748
4938
  navSlot,
4749
- /* @__PURE__ */ jsx98(Pressable31, { onPress: () => setShowNav(false), className: "border-t border-border p-3", children: /* @__PURE__ */ jsx98(Text41, { className: "text-center text-sm font-medium text-primary", children: "Done" }) })
4750
- ] }) : /* @__PURE__ */ jsxs57(View63, { className: "flex-1", children: [
4751
- /* @__PURE__ */ jsx98(Pressable31, { onPress: () => setShowNav(true), className: "border-b border-border px-4 py-2", children: /* @__PURE__ */ jsx98(Text41, { className: "text-sm font-medium text-primary", children: "Menu" }) }),
4939
+ /* @__PURE__ */ jsx100(Pressable32, { onPress: () => setShowNav(false), className: "border-t border-border p-3", children: /* @__PURE__ */ jsx100(Text42, { className: "text-center text-sm font-medium text-primary", children: "Done" }) })
4940
+ ] }) : /* @__PURE__ */ jsxs59(View65, { className: "flex-1", children: [
4941
+ /* @__PURE__ */ jsx100(Pressable32, { onPress: () => setShowNav(true), className: "border-b border-border px-4 py-2", children: /* @__PURE__ */ jsx100(Text42, { className: "text-sm font-medium text-primary", children: "Menu" }) }),
4752
4942
  contentSlot
4753
4943
  ] }) })
4754
4944
  ] });
4755
4945
  }
4756
4946
 
4757
4947
  // src/layout/live-tab-screen.tsx
4758
- import { Pressable as Pressable32, Text as Text42, View as View64 } from "react-native";
4948
+ import { Pressable as Pressable33, Text as Text43, View as View66 } from "react-native";
4759
4949
  import { cn as cn83 } from "@tallyui/theme";
4760
- import { jsx as jsx99, jsxs as jsxs58 } from "react/jsx-runtime";
4950
+ import { jsx as jsx101, jsxs as jsxs60 } from "react/jsx-runtime";
4761
4951
  function LiveTabScreen({
4762
4952
  state,
4763
4953
  onUseHere,
@@ -4774,21 +4964,21 @@ function LiveTabScreen({
4774
4964
  const body = state === "parked" ? parkedBody : blockedBody;
4775
4965
  const buttonLabel = state === "parked" ? useHereLabel : reloadLabel;
4776
4966
  const onPress = state === "parked" ? onUseHere : onReload;
4777
- return /* @__PURE__ */ jsxs58(View64, { className: cn83("flex-1 items-center justify-center gap-4 bg-bg p-6", className), ...viewProps, children: [
4778
- /* @__PURE__ */ jsx99(Text42, { className: "text-center text-lg font-bold text-foreground", children: parkedTitle }),
4779
- /* @__PURE__ */ jsx99(Text42, { className: "text-center text-sm text-muted-foreground", children: body }),
4780
- /* @__PURE__ */ jsx99(Pressable32, { onPress, className: "items-center rounded-lg bg-primary px-4 py-3", children: /* @__PURE__ */ jsx99(Text42, { className: "text-sm font-semibold text-primary-foreground", children: buttonLabel }) })
4967
+ return /* @__PURE__ */ jsxs60(View66, { className: cn83("flex-1 items-center justify-center gap-4 bg-bg p-6", className), ...viewProps, children: [
4968
+ /* @__PURE__ */ jsx101(Text43, { className: "text-center text-lg font-bold text-foreground", children: parkedTitle }),
4969
+ /* @__PURE__ */ jsx101(Text43, { className: "text-center text-sm text-muted-foreground", children: body }),
4970
+ /* @__PURE__ */ jsx101(Pressable33, { onPress, className: "items-center rounded-lg bg-primary px-4 py-3", children: /* @__PURE__ */ jsx101(Text43, { className: "text-sm font-semibold text-primary-foreground", children: buttonLabel }) })
4781
4971
  ] });
4782
4972
  }
4783
4973
 
4784
4974
  // src/layout/store-settings-choice-screen.tsx
4785
- import { useState as useState22 } from "react";
4786
- import { Pressable as Pressable33, Text as Text43, View as View65 } from "react-native";
4975
+ import { useState as useState25 } from "react";
4976
+ import { Pressable as Pressable34, Text as Text44, View as View67 } from "react-native";
4787
4977
  import { cn as cn84 } from "@tallyui/theme";
4788
- import { jsx as jsx100, jsxs as jsxs59 } from "react/jsx-runtime";
4978
+ import { jsx as jsx102, jsxs as jsxs61 } from "react/jsx-runtime";
4789
4979
  function useSectionSelection(options, initialValue) {
4790
4980
  const preset = options.length === 1 ? options[0].value : options.find((o) => o.value === initialValue)?.value;
4791
- return useState22(preset);
4981
+ return useState25(preset);
4792
4982
  }
4793
4983
  function defaultCountryName(code, locale) {
4794
4984
  try {
@@ -4834,32 +5024,32 @@ function StoreSettingsChoiceScreen({
4834
5024
  else if (initial?.channel !== void 0) choice.channel = initial.channel;
4835
5025
  onSubmit(choice);
4836
5026
  };
4837
- return /* @__PURE__ */ jsxs59(View65, { className: cn84("w-full max-w-[560px] flex-1 self-center gap-6 bg-bg p-6", className), ...viewProps, children: [
4838
- /* @__PURE__ */ jsxs59(View65, { className: "gap-2", children: [
4839
- /* @__PURE__ */ jsx100(Text43, { className: "text-lg font-bold text-foreground", children: title }),
4840
- /* @__PURE__ */ jsx100(Text43, { className: "text-sm text-muted-foreground", children: body })
5027
+ return /* @__PURE__ */ jsxs61(View67, { className: cn84("w-full max-w-[560px] flex-1 self-center gap-6 bg-bg p-6", className), ...viewProps, children: [
5028
+ /* @__PURE__ */ jsxs61(View67, { className: "gap-2", children: [
5029
+ /* @__PURE__ */ jsx102(Text44, { className: "text-lg font-bold text-foreground", children: title }),
5030
+ /* @__PURE__ */ jsx102(Text44, { className: "text-sm text-muted-foreground", children: body })
4841
5031
  ] }),
4842
- showRegions && /* @__PURE__ */ jsx100(ChoiceSection, { label: regionLabel, options: regionOptions, selected: region, onSelect: setRegion }),
4843
- showCountries && /* @__PURE__ */ jsx100(ChoiceSection, { label: countryLabel, options: countryOptions, selected: country, onSelect: setCountry }),
4844
- showChannels && /* @__PURE__ */ jsx100(ChoiceSection, { label: channelLabel, options: channelOptions, selected: channel, onSelect: setChannel }),
4845
- /* @__PURE__ */ jsx100(
4846
- Pressable33,
5032
+ showRegions && /* @__PURE__ */ jsx102(ChoiceSection, { label: regionLabel, options: regionOptions, selected: region, onSelect: setRegion }),
5033
+ showCountries && /* @__PURE__ */ jsx102(ChoiceSection, { label: countryLabel, options: countryOptions, selected: country, onSelect: setCountry }),
5034
+ showChannels && /* @__PURE__ */ jsx102(ChoiceSection, { label: channelLabel, options: channelOptions, selected: channel, onSelect: setChannel }),
5035
+ /* @__PURE__ */ jsx102(
5036
+ Pressable34,
4847
5037
  {
4848
5038
  onPress: handleSubmit,
4849
5039
  disabled: !complete,
4850
5040
  className: cn84("items-center rounded-lg bg-primary px-4 py-3", !complete && "opacity-50"),
4851
- children: /* @__PURE__ */ jsx100(Text43, { className: "text-sm font-semibold text-primary-foreground", children: submitLabel })
5041
+ children: /* @__PURE__ */ jsx102(Text44, { className: "text-sm font-semibold text-primary-foreground", children: submitLabel })
4852
5042
  }
4853
5043
  )
4854
5044
  ] });
4855
5045
  }
4856
5046
  function ChoiceSection({ label, options, selected, onSelect }) {
4857
- return /* @__PURE__ */ jsxs59(View65, { className: "gap-1.5", children: [
4858
- /* @__PURE__ */ jsx100(Text43, { className: "text-xs font-semibold text-muted-foreground", children: label }),
4859
- /* @__PURE__ */ jsx100(View65, { className: "rounded-lg border border-border", children: options.map((option, index) => {
5047
+ return /* @__PURE__ */ jsxs61(View67, { className: "gap-1.5", children: [
5048
+ /* @__PURE__ */ jsx102(Text44, { className: "text-xs font-semibold text-muted-foreground", children: label }),
5049
+ /* @__PURE__ */ jsx102(View67, { className: "rounded-lg border border-border", children: options.map((option, index) => {
4860
5050
  const checked = option.value === selected;
4861
- return /* @__PURE__ */ jsxs59(
4862
- Pressable33,
5051
+ return /* @__PURE__ */ jsxs61(
5052
+ Pressable34,
4863
5053
  {
4864
5054
  onPress: () => onSelect(option.value),
4865
5055
  accessibilityRole: "radio",
@@ -4867,8 +5057,8 @@ function ChoiceSection({ label, options, selected, onSelect }) {
4867
5057
  testID: `choice-option-${option.value}`,
4868
5058
  className: cn84("flex-row items-center gap-3 px-4 py-3", index > 0 && "border-t border-border", checked && "bg-primary/10"),
4869
5059
  children: [
4870
- /* @__PURE__ */ jsx100(View65, { className: "h-4 w-4 items-center justify-center rounded-full border border-primary", children: checked && /* @__PURE__ */ jsx100(View65, { testID: `choice-option-${option.value}-dot`, className: "h-2.5 w-2.5 rounded-full bg-primary" }) }),
4871
- /* @__PURE__ */ jsx100(Text43, { className: cn84("text-sm", checked ? "font-semibold text-primary" : "text-foreground"), children: option.label })
5060
+ /* @__PURE__ */ jsx102(View67, { className: "h-4 w-4 items-center justify-center rounded-full border border-primary", children: checked && /* @__PURE__ */ jsx102(View67, { testID: `choice-option-${option.value}-dot`, className: "h-2.5 w-2.5 rounded-full bg-primary" }) }),
5061
+ /* @__PURE__ */ jsx102(Text44, { className: cn84("text-sm", checked ? "font-semibold text-primary" : "text-foreground"), children: option.label })
4872
5062
  ]
4873
5063
  },
4874
5064
  option.value
@@ -4998,11 +5188,13 @@ export {
4998
5188
  OrderSummaryLine,
4999
5189
  OrdersList,
5000
5190
  POSLayout,
5191
+ ParkedSales,
5001
5192
  PaymentMethodCard,
5002
5193
  PaymentSelector,
5003
5194
  Popover,
5004
5195
  PopoverContent,
5005
5196
  PopoverTrigger,
5197
+ PriceForm,
5006
5198
  ProductCard,
5007
5199
  ProductGrid,
5008
5200
  ProductImage,
@@ -5086,6 +5278,7 @@ export {
5086
5278
  loaderVariants,
5087
5279
  orderReference,
5088
5280
  parseDiscount,
5281
+ parsePrice,
5089
5282
  textVariants,
5090
5283
  toastVariants,
5091
5284
  toggleTextVariants,